Auto fix standard style voilations

This commit is contained in:
Tyler Long
2017-04-11 22:14:25 +08:00
parent d46fda537d
commit 620f3e8734
66 changed files with 45436 additions and 45726 deletions

View File

@@ -1,15 +1,15 @@
var Logger = require('../../logger');
var log = Logger.Log;
var relations = [];
var Logger = require('../../logger')
var log = Logger.Log
var relations = []
var classes;
var idCache;
var classes
var idCache
classes = {
};
}
// Functions to be run after graph rendering
var funs = [];
var funs = []
/**
* Function called by parser when a node definition has been found.
* @param id
@@ -18,69 +18,66 @@ var funs = [];
* @param style
*/
exports.addClass = function (id) {
if(typeof classes[id] === 'undefined'){
classes[id] = {
id:id,
methods:[],
members:[]
};
if (typeof classes[id] === 'undefined') {
classes[id] = {
id: id,
methods: [],
members: []
}
};
}
}
exports.clear = function () {
relations = [];
classes = {};
};
relations = []
classes = {}
}
module.exports.getClass = function (id) {
return classes[id];
};
return classes[id]
}
module.exports.getClasses = function () {
return classes;
};
return classes
}
module.exports.getRelations = function () {
return relations;
};
return relations
}
exports.addRelation = function (relation) {
log.warn('Adding relation: ' + JSON.stringify(relation));
exports.addClass(relation.id1);
exports.addClass(relation.id2);
log.warn('Adding relation: ' + JSON.stringify(relation))
exports.addClass(relation.id1)
exports.addClass(relation.id2)
relations.push(relation);
};
relations.push(relation)
}
exports.addMembers = function (className, MembersArr) {
var theClass = classes[className];
if(typeof MembersArr === 'string'){
if(MembersArr.substr(-1) === ')'){
theClass.methods.push(MembersArr);
}
else{
theClass.members.push(MembersArr);
}
var theClass = classes[className]
if (typeof MembersArr === 'string') {
if (MembersArr.substr(-1) === ')') {
theClass.methods.push(MembersArr)
} else {
theClass.members.push(MembersArr)
}
};
}
}
exports.cleanupLabel = function (label) {
if(label.substring(0,1) === ':'){
return label.substr(2).trim();
}
else{
return label.trim();
}
};
if (label.substring(0, 1) === ':') {
return label.substr(2).trim()
} else {
return label.trim()
}
}
exports.lineType = {
LINE:0,
DOTTED_LINE:1
};
LINE: 0,
DOTTED_LINE: 1
}
exports.relationType = {
AGGREGATION:0,
EXTENSION:1,
COMPOSITION:2,
DEPENDENCY:3
};
AGGREGATION: 0,
EXTENSION: 1,
COMPOSITION: 2,
DEPENDENCY: 3
}

View File

@@ -2,213 +2,212 @@
* Created by knut on 14-11-18.
*/
describe('class diagram, ', function () {
describe('when parsing an info graph it', function () {
var cd, cDDb;
beforeEach(function () {
cd = require('./parser/classDiagram').parser;
cDDb = require('./classDb');
cd.yy = cDDb;
});
describe('when parsing an info graph it', function () {
var cd, cDDb
beforeEach(function () {
cd = require('./parser/classDiagram').parser
cDDb = require('./classDb')
cd.yy = cDDb
})
it('should handle relation definitions', function () {
var str = 'classDiagram\n'+
'Class01 <|-- Class02\n'+
'Class03 *-- Class04\n'+
'Class05 o-- Class06\n'+
'Class07 .. Class08\n'+
'Class09 -- Class1';
it('should handle relation definitions', function () {
var str = 'classDiagram\n' +
'Class01 <|-- Class02\n' +
'Class03 *-- Class04\n' +
'Class05 o-- Class06\n' +
'Class07 .. Class08\n' +
'Class09 -- Class1'
cd.parse(str);
});
it('should handle relation definition of different types and directions', function () {
var str = 'classDiagram\n'+
'Class11 <|.. Class12\n'+
'Class13 --> Class14\n'+
'Class15 ..> Class16\n'+
'Class17 ..|> Class18\n'+
'Class19 <--* Class20';
cd.parse(str)
})
it('should handle relation definition of different types and directions', function () {
var str = 'classDiagram\n' +
'Class11 <|.. Class12\n' +
'Class13 --> Class14\n' +
'Class15 ..> Class16\n' +
'Class17 ..|> Class18\n' +
'Class19 <--* Class20'
cd.parse(str);
});
cd.parse(str)
})
it('should handle cardinality and labels', function () {
var str = 'classDiagram\n'+
'Class01 "1" *-- "many" Class02 : contains\n'+
'Class03 o-- Class04 : aggregation\n'+
'Class05 --> "1" Class06';
it('should handle cardinality and labels', function () {
var str = 'classDiagram\n' +
'Class01 "1" *-- "many" Class02 : contains\n' +
'Class03 o-- Class04 : aggregation\n' +
'Class05 --> "1" Class06'
cd.parse(str);
});
it('should handle class definitions', function () {
var str = 'classDiagram\n'+
'class Car\n'+
'Driver -- Car : drives >\n'+
'Car *-- Wheel : have 4 >\n'+
'Car -- Person : < owns';
cd.parse(str)
})
it('should handle class definitions', function () {
var str = 'classDiagram\n' +
'class Car\n' +
'Driver -- Car : drives >\n' +
'Car *-- Wheel : have 4 >\n' +
'Car -- Person : < owns'
cd.parse(str);
});
cd.parse(str)
})
it('should handle method statements', function () {
var str = 'classDiagram\n'+
'Object <|-- ArrayList\n'+
'Object : equals()\n'+
'ArrayList : Object[] elementData\n'+
'ArrayList : size()';
it('should handle method statements', function () {
var str = 'classDiagram\n' +
'Object <|-- ArrayList\n' +
'Object : equals()\n' +
'ArrayList : Object[] elementData\n' +
'ArrayList : size()'
cd.parse(str);
});
it('should handle parsing of method statements grouped by brackets', function () {
var str = 'classDiagram\n'+
'class Dummy {\n'+
'String data\n'+
' void methods()\n'+
'}\n'+
'\n'+
'class Flight {\n'+
' flightNumber : Integer\n'+
' departureTime : Date\n'+
'}';
cd.parse(str)
})
it('should handle parsing of method statements grouped by brackets', function () {
var str = 'classDiagram\n' +
'class Dummy {\n' +
'String data\n' +
' void methods()\n' +
'}\n' +
'\n' +
'class Flight {\n' +
' flightNumber : Integer\n' +
' departureTime : Date\n' +
'}'
cd.parse(str);
});
cd.parse(str)
})
it('should handle parsing of separators', function () {
var str = 'classDiagram\n'+
'class Foo1 {\n'+
' You can use\n'+
' several lines\n'+
'..\n'+
'as you want\n'+
'and group\n'+
'==\n'+
'things together.\n'+
'__\n'+
'You can have as many groups\n'+
'as you want\n'+
'--\n'+
'End of class\n'+
'}\n'+
'\n'+
'class User {\n'+
'.. Simple Getter ..\n'+
'+ getName()\n'+
'+ getAddress()\n'+
'.. Some setter ..\n'+
'+ setName()\n'+
'__ private data __\n'+
'int age\n'+
'-- encrypted --\n'+
'String password\n'+
'}';
it('should handle parsing of separators', function () {
var str = 'classDiagram\n' +
'class Foo1 {\n' +
' You can use\n' +
' several lines\n' +
'..\n' +
'as you want\n' +
'and group\n' +
'==\n' +
'things together.\n' +
'__\n' +
'You can have as many groups\n' +
'as you want\n' +
'--\n' +
'End of class\n' +
'}\n' +
'\n' +
'class User {\n' +
'.. Simple Getter ..\n' +
'+ getName()\n' +
'+ getAddress()\n' +
'.. Some setter ..\n' +
'+ setName()\n' +
'__ private data __\n' +
'int age\n' +
'-- encrypted --\n' +
'String password\n' +
'}'
cd.parse(str);
});
cd.parse(str)
})
})
});
describe('when fetching data from an classDiagram graph it', function () {
var cd, cDDb
beforeEach(function () {
cd = require('./parser/classDiagram').parser
cDDb = require('./classDb')
cd.yy = cDDb
cd.yy.clear()
})
it('should handle relation definitions EXTENSION', function () {
var str = 'classDiagram\n' +
'Class01 <|-- Class02'
describe('when fetching data from an classDiagram graph it', function () {
var cd, cDDb;
beforeEach(function () {
cd = require('./parser/classDiagram').parser;
cDDb = require('./classDb');
cd.yy = cDDb;
cd.yy.clear();
});
it('should handle relation definitions EXTENSION', function () {
var str = 'classDiagram\n'+
'Class01 <|-- Class02';
cd.parse(str)
cd.parse(str);
var relations = cd.yy.getRelations()
var relations = cd.yy.getRelations();
expect(cd.yy.getClass('Class01').id).toBe('Class01')
expect(cd.yy.getClass('Class02').id).toBe('Class02')
expect(relations[0].relation.type1).toBe(cDDb.relationType.EXTENSION)
expect(relations[0].relation.type2).toBe('none')
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE)
})
it('should handle relation definitions AGGREGATION and dotted line', function () {
var str = 'classDiagram\n' +
'Class01 o.. Class02'
expect(cd.yy.getClass('Class01').id).toBe('Class01');
expect(cd.yy.getClass('Class02').id).toBe('Class02');
expect(relations[0].relation.type1).toBe(cDDb.relationType.EXTENSION);
expect(relations[0].relation.type2).toBe('none');
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE);
});
it('should handle relation definitions AGGREGATION and dotted line', function () {
var str = 'classDiagram\n'+
'Class01 o.. Class02';
cd.parse(str)
cd.parse(str);
var relations = cd.yy.getRelations()
var relations = cd.yy.getRelations();
expect(cd.yy.getClass('Class01').id).toBe('Class01')
expect(cd.yy.getClass('Class02').id).toBe('Class02')
expect(relations[0].relation.type1).toBe(cDDb.relationType.AGGREGATION)
expect(relations[0].relation.type2).toBe('none')
expect(relations[0].relation.lineType).toBe(cDDb.lineType.DOTTED_LINE)
})
it('should handle relation definitions COMPOSITION on both sides', function () {
var str = 'classDiagram\n' +
'Class01 *--* Class02'
expect(cd.yy.getClass('Class01').id).toBe('Class01');
expect(cd.yy.getClass('Class02').id).toBe('Class02');
expect(relations[0].relation.type1).toBe(cDDb.relationType.AGGREGATION);
expect(relations[0].relation.type2).toBe('none');
expect(relations[0].relation.lineType).toBe(cDDb.lineType.DOTTED_LINE);
});
it('should handle relation definitions COMPOSITION on both sides', function () {
var str = 'classDiagram\n'+
'Class01 *--* Class02';
cd.parse(str)
cd.parse(str);
var relations = cd.yy.getRelations()
var relations = cd.yy.getRelations();
expect(cd.yy.getClass('Class01').id).toBe('Class01')
expect(cd.yy.getClass('Class02').id).toBe('Class02')
expect(relations[0].relation.type1).toBe(cDDb.relationType.COMPOSITION)
expect(relations[0].relation.type2).toBe(cDDb.relationType.COMPOSITION)
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE)
})
it('should handle relation definitions no types', function () {
var str = 'classDiagram\n' +
'Class01 -- Class02'
expect(cd.yy.getClass('Class01').id).toBe('Class01');
expect(cd.yy.getClass('Class02').id).toBe('Class02');
expect(relations[0].relation.type1).toBe(cDDb.relationType.COMPOSITION);
expect(relations[0].relation.type2).toBe(cDDb.relationType.COMPOSITION);
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE);
});
it('should handle relation definitions no types', function () {
var str = 'classDiagram\n'+
'Class01 -- Class02';
cd.parse(str)
cd.parse(str);
var relations = cd.yy.getRelations()
var relations = cd.yy.getRelations();
expect(cd.yy.getClass('Class01').id).toBe('Class01')
expect(cd.yy.getClass('Class02').id).toBe('Class02')
expect(relations[0].relation.type1).toBe('none')
expect(relations[0].relation.type2).toBe('none')
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE)
})
it('should handle relation definitions with type only on right side', function () {
var str = 'classDiagram\n' +
'Class01 --|> Class02'
expect(cd.yy.getClass('Class01').id).toBe('Class01');
expect(cd.yy.getClass('Class02').id).toBe('Class02');
expect(relations[0].relation.type1).toBe('none');
expect(relations[0].relation.type2).toBe('none');
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE);
});
it('should handle relation definitions with type only on right side', function () {
var str = 'classDiagram\n'+
'Class01 --|> Class02';
cd.parse(str)
cd.parse(str);
var relations = cd.yy.getRelations()
var relations = cd.yy.getRelations();
expect(cd.yy.getClass('Class01').id).toBe('Class01')
expect(cd.yy.getClass('Class02').id).toBe('Class02')
expect(relations[0].relation.type1).toBe('none')
expect(relations[0].relation.type2).toBe(cDDb.relationType.EXTENSION)
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE)
})
expect(cd.yy.getClass('Class01').id).toBe('Class01');
expect(cd.yy.getClass('Class02').id).toBe('Class02');
expect(relations[0].relation.type1).toBe('none');
expect(relations[0].relation.type2).toBe(cDDb.relationType.EXTENSION);
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE);
});
it('should handle multiple classes and relation definitions', function () {
var str = 'classDiagram\n' +
'Class01 <|-- Class02\n' +
'Class03 *-- Class04\n' +
'Class05 o-- Class06\n' +
'Class07 .. Class08\n' +
'Class09 -- Class10'
it('should handle multiple classes and relation definitions', function () {
var str = 'classDiagram\n'+
'Class01 <|-- Class02\n'+
'Class03 *-- Class04\n'+
'Class05 o-- Class06\n'+
'Class07 .. Class08\n'+
'Class09 -- Class10';
cd.parse(str)
cd.parse(str);
var relations = cd.yy.getRelations()
var relations = cd.yy.getRelations();
expect(cd.yy.getClass('Class01').id).toBe('Class01')
expect(cd.yy.getClass('Class10').id).toBe('Class10')
expect(cd.yy.getClass('Class01').id).toBe('Class01');
expect(cd.yy.getClass('Class10').id).toBe('Class10');
expect(relations.length).toBe(5)
expect(relations.length).toBe(5);
expect(relations[0].relation.type1).toBe(cDDb.relationType.EXTENSION);
expect(relations[0].relation.type2).toBe('none');
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE);
expect(relations[3].relation.type1).toBe('none');
expect(relations[3].relation.type2).toBe('none');
expect(relations[3].relation.lineType).toBe(cDDb.lineType.DOTTED_LINE);
});
});
});
expect(relations[0].relation.type1).toBe(cDDb.relationType.EXTENSION)
expect(relations[0].relation.type2).toBe('none')
expect(relations[0].relation.lineType).toBe(cDDb.lineType.LINE)
expect(relations[3].relation.type1).toBe('none')
expect(relations[3].relation.type2).toBe('none')
expect(relations[3].relation.lineType).toBe(cDDb.lineType.DOTTED_LINE)
})
})
})

View File

@@ -2,43 +2,43 @@
* Created by knut on 14-11-23.
*/
var cd = require('./parser/classDiagram').parser;
var cDDb = require('./classDb');
cd.yy = cDDb;
var d3 = require('../../d3');
var Logger = require('../../logger');
var log = Logger.Log;
var dagre = require('dagre');
var cd = require('./parser/classDiagram').parser
var cDDb = require('./classDb')
cd.yy = cDDb
var d3 = require('../../d3')
var Logger = require('../../logger')
var log = Logger.Log
var dagre = require('dagre')
var idCache;
idCache = {};
var idCache
idCache = {}
var classCnt = 0;
var classCnt = 0
var conf = {
dividerMargin: 10,
padding: 5,
textHeight: 14
};
dividerMargin: 10,
padding: 5,
textHeight: 14
}
// Todo optimize
var getGraphId = function (label) {
var keys = Object.keys(idCache);
var keys = Object.keys(idCache)
var i;
for(i=0;i<keys.length;i++){
if(idCache[keys[i]].label === label){
return keys[i];
}
var i
for (i = 0; i < keys.length; i++) {
if (idCache[keys[i]].label === label) {
return keys[i]
}
}
return undefined;
return undefined
}
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
var insertMarkers = function (elem) {
elem.append('defs').append('marker')
elem.append('defs').append('marker')
.attr('id', 'extensionStart')
.attr('class', 'extension')
.attr('refX', 0)
@@ -47,9 +47,9 @@ var insertMarkers = function (elem) {
.attr('markerHeight', 240)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 1,7 L18,13 V 1 Z');
.attr('d', 'M 1,7 L18,13 V 1 Z')
elem.append('defs').append('marker')
elem.append('defs').append('marker')
.attr('id', 'extensionEnd')
.attr('refX', 19)
.attr('refY', 7)
@@ -57,9 +57,9 @@ var insertMarkers = function (elem) {
.attr('markerHeight', 28)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 1,1 V 13 L18,7 Z'); //this is actual shape for arrowhead
.attr('d', 'M 1,1 V 13 L18,7 Z') // this is actual shape for arrowhead
elem.append('defs').append('marker')
elem.append('defs').append('marker')
.attr('id', 'compositionStart')
.attr('class', 'extension')
.attr('refX', 0)
@@ -68,9 +68,9 @@ var insertMarkers = function (elem) {
.attr('markerHeight', 240)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z');
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z')
elem.append('defs').append('marker')
elem.append('defs').append('marker')
.attr('id', 'compositionEnd')
.attr('refX', 19)
.attr('refY', 7)
@@ -78,10 +78,9 @@ var insertMarkers = function (elem) {
.attr('markerHeight', 28)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z');
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z')
elem.append('defs').append('marker')
elem.append('defs').append('marker')
.attr('id', 'aggregationStart')
.attr('class', 'extension')
.attr('refX', 0)
@@ -90,9 +89,9 @@ var insertMarkers = function (elem) {
.attr('markerHeight', 240)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z');
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z')
elem.append('defs').append('marker')
elem.append('defs').append('marker')
.attr('id', 'aggregationEnd')
.attr('refX', 19)
.attr('refY', 7)
@@ -100,9 +99,9 @@ var insertMarkers = function (elem) {
.attr('markerHeight', 28)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z');
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z')
elem.append('defs').append('marker')
elem.append('defs').append('marker')
.attr('id', 'dependencyStart')
.attr('class', 'extension')
.attr('refX', 0)
@@ -111,9 +110,9 @@ var insertMarkers = function (elem) {
.attr('markerHeight', 240)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 5,7 L9,13 L1,7 L9,1 Z');
.attr('d', 'M 5,7 L9,13 L1,7 L9,1 Z')
elem.append('defs').append('marker')
elem.append('defs').append('marker')
.attr('id', 'dependencyEnd')
.attr('refX', 19)
.attr('refY', 7)
@@ -121,302 +120,293 @@ var insertMarkers = function (elem) {
.attr('markerHeight', 28)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z');
};
.attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z')
}
var edgeCount = 0;
var edgeCount = 0
var drawEdge = function (elem, path, relation) {
var getRelationType = function (type) {
switch (type) {
case cDDb.relationType.AGGREGATION:
return 'aggregation';
case cDDb.relationType.EXTENSION:
return 'extension';
case cDDb.relationType.COMPOSITION:
return 'composition';
case cDDb.relationType.DEPENDENCY:
return 'dependency';
}
};
var getRelationType = function (type) {
switch (type) {
case cDDb.relationType.AGGREGATION:
return 'aggregation'
case cDDb.relationType.EXTENSION:
return 'extension'
case cDDb.relationType.COMPOSITION:
return 'composition'
case cDDb.relationType.DEPENDENCY:
return 'dependency'
}
}
// The data for our line
var lineData = path.points
//The data for our line
var lineData = path.points;
//This is the accessor function we talked about above
var lineFunction = d3.svg.line()
// This is the accessor function we talked about above
var lineFunction = d3.svg.line()
.x(function (d) {
return d.x;
return d.x
})
.y(function (d) {
return d.y;
return d.y
})
//.interpolate('cardinal');
.interpolate('basis');
// .interpolate('cardinal');
.interpolate('basis')
var svgPath = elem.append('path')
var svgPath = elem.append('path')
.attr('d', lineFunction(lineData))
.attr('id', 'edge' + edgeCount)
.attr('class', 'relation');
var url = '';
if(conf.arrowMarkerAbsolute){
url = window.location.protocol+'//'+window.location.host+window.location.pathname +window.location.search;
url = url.replace(/\(/g,'\\(');
url = url.replace(/\)/g,'\\)');
}
.attr('class', 'relation')
var url = ''
if (conf.arrowMarkerAbsolute) {
url = window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search
url = url.replace(/\(/g, '\\(')
url = url.replace(/\)/g, '\\)')
}
//console.log(relation.relation.type1);
if (relation.relation.type1 !== 'none') {
svgPath.attr('marker-start', 'url(' + url + '#' + getRelationType(relation.relation.type1) + 'Start' + ')');
}
if (relation.relation.type2 !== 'none') {
svgPath.attr('marker-end', 'url(' + url + '#' + getRelationType(relation.relation.type2) + 'End' + ')');
}
// console.log(relation.relation.type1);
if (relation.relation.type1 !== 'none') {
svgPath.attr('marker-start', 'url(' + url + '#' + getRelationType(relation.relation.type1) + 'Start' + ')')
}
if (relation.relation.type2 !== 'none') {
svgPath.attr('marker-end', 'url(' + url + '#' + getRelationType(relation.relation.type2) + 'End' + ')')
}
//var bbox = svgPath[0][0].getBBox();
//var x = Math.floor(bbox.x + bbox.width/2.0);
//var y = Math.floor(bbox.y + bbox.height/2.0);
var x, y;
var l = path.points.length;
if ((l % 2) !== 0) {
var p1 = path.points[Math.floor(l / 2)];
var p2 = path.points[Math.ceil(l / 2)];
x = (p1.x + p2.x) / 2;
y = (p1.y + p2.y) / 2;
}
else {
var p = path.points[Math.floor(l / 2)];
x = p.x;
y = p.y;
}
// var bbox = svgPath[0][0].getBBox();
// var x = Math.floor(bbox.x + bbox.width/2.0);
// var y = Math.floor(bbox.y + bbox.height/2.0);
var x, y
var l = path.points.length
if ((l % 2) !== 0) {
var p1 = path.points[Math.floor(l / 2)]
var p2 = path.points[Math.ceil(l / 2)]
x = (p1.x + p2.x) / 2
y = (p1.y + p2.y) / 2
} else {
var p = path.points[Math.floor(l / 2)]
x = p.x
y = p.y
}
if (typeof relation.title !== 'undefined') {
var g = elem.append('g').
attr('class','classLabel');
var label = g.append('text')
if (typeof relation.title !== 'undefined') {
var g = elem.append('g')
.attr('class', 'classLabel')
var label = g.append('text')
.attr('class', 'label')
.attr('x', x)
.attr('y', y)
.attr('fill', 'red')
.attr('text-anchor', 'middle')
.text(relation.title);
.text(relation.title)
window.label = label;
var bounds = label.node().getBBox();
window.label = label
var bounds = label.node().getBBox()
g.insert('rect', ':first-child')
g.insert('rect', ':first-child')
.attr('class', 'box')
.attr('x', bounds.x-conf.padding/2)
.attr('y', bounds.y-conf.padding/2)
.attr('width', bounds.width + 2 * conf.padding/2)
.attr('height', bounds.height + 2 * conf.padding/2);
//.append('textpath')
//.attr('xlink:href','#edge'+edgeCount)
//.attr('text-anchor','middle')
//.attr('startOffset','50%')
.attr('x', bounds.x - conf.padding / 2)
.attr('y', bounds.y - conf.padding / 2)
.attr('width', bounds.width + 2 * conf.padding / 2)
.attr('height', bounds.height + 2 * conf.padding / 2)
// .append('textpath')
// .attr('xlink:href','#edge'+edgeCount)
// .attr('text-anchor','middle')
// .attr('startOffset','50%')
}
}
edgeCount++;
edgeCount++
}
var drawClass = function (elem, classDef) {
log.info('Rendering class ' + classDef);
log.info('Rendering class ' + classDef)
var addTspan = function (textEl, txt, isFirst) {
var tSpan = textEl.append('tspan')
var addTspan = function (textEl, txt, isFirst) {
var tSpan = textEl.append('tspan')
.attr('x', conf.padding)
.text(txt);
if (!isFirst) {
tSpan.attr('dy', conf.textHeight);
}
};
.text(txt)
if (!isFirst) {
tSpan.attr('dy', conf.textHeight)
}
}
var id = 'classId' + classCnt;
var classInfo = {
id: id,
label: classDef.id,
width: 0,
height: 0
};
var id = 'classId' + classCnt
var classInfo = {
id: id,
label: classDef.id,
width: 0,
height: 0
}
var g = elem.append('g')
var g = elem.append('g')
.attr('id', id)
.attr('class', 'classGroup');
var title = g.append('text')
.attr('class', 'classGroup')
var title = g.append('text')
.attr('x', conf.padding)
.attr('y', conf.textHeight + conf.padding)
.text(classDef.id);
.text(classDef.id)
var titleHeight = title.node().getBBox().height;
var titleHeight = title.node().getBBox().height
var membersLine = g.append('line') // text label for the x axis
var membersLine = g.append('line') // text label for the x axis
.attr('x1', 0)
.attr('y1', conf.padding + titleHeight + conf.dividerMargin / 2)
.attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2);
.attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2)
var members = g.append('text') // text label for the x axis
var members = g.append('text') // text label for the x axis
.attr('x', conf.padding)
.attr('y', titleHeight + (conf.dividerMargin) + conf.textHeight)
.attr('fill', 'white')
.attr('class', 'classText');
.attr('class', 'classText')
var isFirst = true;
var isFirst = true
classDef.members.forEach(function(member){
addTspan(members, member, isFirst);
isFirst = false;
});
//for (var member of classDef.members) {
classDef.members.forEach(function (member) {
addTspan(members, member, isFirst)
isFirst = false
})
// for (var member of classDef.members) {
// addTspan(members, member, isFirst);
// isFirst = false;
//}
// }
var membersBox = members.node().getBBox();
var membersBox = members.node().getBBox()
var methodsLine = g.append('line') // text label for the x axis
var methodsLine = g.append('line') // text label for the x axis
.attr('x1', 0)
.attr('y1', conf.padding + titleHeight + 3 * conf.dividerMargin / 2 + membersBox.height)
.attr('y2', conf.padding + titleHeight + 3 * conf.dividerMargin / 2 + membersBox.height);
.attr('y2', conf.padding + titleHeight + 3 * conf.dividerMargin / 2 + membersBox.height)
var methods = g.append('text') // text label for the x axis
var methods = g.append('text') // text label for the x axis
.attr('x', conf.padding)
.attr('y', titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight)
.attr('fill', 'white')
.attr('class', 'classText');
.attr('class', 'classText')
isFirst = true;
isFirst = true
classDef.methods.forEach(function(method){
addTspan(methods, method, isFirst);
isFirst = false;
});
//for (var method of classDef.methods) {
classDef.methods.forEach(function (method) {
addTspan(methods, method, isFirst)
isFirst = false
})
// for (var method of classDef.methods) {
// addTspan(methods, method, isFirst);
// isFirst = false;
//}
// }
var classBox = g.node().getBBox();
g.insert('rect', ':first-child')
var classBox = g.node().getBBox()
g.insert('rect', ':first-child')
.attr('x', 0)
.attr('y', 0)
.attr('width', classBox.width + 2 * conf.padding)
.attr('height', classBox.height + conf.padding + 0.5 * conf.dividerMargin);
.attr('height', classBox.height + conf.padding + 0.5 * conf.dividerMargin)
membersLine.attr('x2', classBox.width + 2 * conf.padding)
methodsLine.attr('x2', classBox.width + 2 * conf.padding)
membersLine.attr('x2', classBox.width + 2 * conf.padding);
methodsLine.attr('x2', classBox.width + 2 * conf.padding);
classInfo.width = classBox.width + 2 * conf.padding;
classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin;
idCache[id] = classInfo;
classCnt++;
return classInfo;
};
classInfo.width = classBox.width + 2 * conf.padding
classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin
idCache[id] = classInfo
classCnt++
return classInfo
}
module.exports.setConf = function (cnf) {
var keys = Object.keys(cnf);
var keys = Object.keys(cnf)
keys.forEach(function (key) {
conf[key] = cnf[key];
});
};
keys.forEach(function (key) {
conf[key] = cnf[key]
})
}
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
* @param text
* @param id
*/
module.exports.draw = function (text, id) {
cd.yy.clear();
cd.parse(text);
cd.yy.clear()
cd.parse(text)
log.info('Rendering diagram ' + text);
log.info('Rendering diagram ' + text)
//// Fetch the default direction, use TD if none was found
var diagram = d3.select('#' + id);
insertMarkers(diagram);
//var svg = diagram.append('svg');
/// / Fetch the default direction, use TD if none was found
var diagram = d3.select('#' + id)
insertMarkers(diagram)
// var svg = diagram.append('svg');
// Layout graph, Create a new directed graph
var g = new dagre.graphlib.Graph({
multigraph: true
});
var g = new dagre.graphlib.Graph({
multigraph: true
})
// Set an object for the graph label
g.setGraph({
isMultiGraph: true
});
g.setGraph({
isMultiGraph: true
})
// Default to assigning a new object as a label for each new edge.
g.setDefaultEdgeLabel(function () {
return {};
});
g.setDefaultEdgeLabel(function () {
return {}
})
var classes = cDDb.getClasses();
var keys = Object.keys(classes);
var i;
for (i=0;i<keys.length;i++) {
var classDef = classes[keys[i]];
var node = drawClass(diagram, classDef);
var classes = cDDb.getClasses()
var keys = Object.keys(classes)
var i
for (i = 0; i < keys.length; i++) {
var classDef = classes[keys[i]]
var node = drawClass(diagram, classDef)
// Add nodes to the graph. The first argument is the node id. The second is
// metadata about the node. In this case we're going to add labels to each of
// our nodes.
g.setNode(node.id, node);
log.info('Org height: ' + node.height);
//g.setNode("swilliams", { label: "Saul Williams", width: 160, height: 100 });
//g.setNode("bpitt", { label: "Brad Pitt", width: 108, height: 100 });
//g.setNode("hford", { label: "Harrison Ford", width: 168, height: 100 });
//g.setNode("lwilson", { label: "Luke Wilson", width: 144, height: 100 });
//g.setNode("kbacon", { label: "Kevin Bacon", width: 121, height: 100 });
}
g.setNode(node.id, node)
log.info('Org height: ' + node.height)
// g.setNode("swilliams", { label: "Saul Williams", width: 160, height: 100 });
// g.setNode("bpitt", { label: "Brad Pitt", width: 108, height: 100 });
// g.setNode("hford", { label: "Harrison Ford", width: 168, height: 100 });
// g.setNode("lwilson", { label: "Luke Wilson", width: 144, height: 100 });
// g.setNode("kbacon", { label: "Kevin Bacon", width: 121, height: 100 });
}
var relations = cDDb.getRelations();
var i = 0;
relations.forEach(function(relation){
i = i + 1;
log.info('tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation));
g.setEdge(getGraphId(relation.id1), getGraphId(relation.id2), {relation: relation});
});
//for (var relation of relations) {
var relations = cDDb.getRelations()
var i = 0
relations.forEach(function (relation) {
i = i + 1
log.info('tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation))
g.setEdge(getGraphId(relation.id1), getGraphId(relation.id2), {relation: relation})
})
// for (var relation of relations) {
// i = i + 1;
// log.info('tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation));
// g.setEdge(getGraphId(relation.id1), getGraphId(relation.id2), {relation: relation});
//}
dagre.layout(g);
g.nodes().forEach(function (v) {
if(typeof v !== 'undefined'){
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
d3.select('#' + v).attr('transform', 'translate(' + (g.node(v).x - (g.node(v).width / 2)) + ',' + (g.node(v).y - (g.node(v).height / 2)) + ' )');
//d3.select('#' +v +' rect').attr('x',(g.node(v).x-(g.node(v).width/2)))
//.attr('y',(g.node(v).y-(g.node(v).height/2)));
}
});
g.edges().forEach(function (e) {
log.debug('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(g.edge(e)));
drawEdge(diagram, g.edge(e), g.edge(e).relation);
});
// }
dagre.layout(g)
g.nodes().forEach(function (v) {
if (typeof v !== 'undefined') {
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)))
d3.select('#' + v).attr('transform', 'translate(' + (g.node(v).x - (g.node(v).width / 2)) + ',' + (g.node(v).y - (g.node(v).height / 2)) + ' )')
// d3.select('#' +v +' rect').attr('x',(g.node(v).x-(g.node(v).width/2)))
// .attr('y',(g.node(v).y-(g.node(v).height/2)));
}
})
g.edges().forEach(function (e) {
log.debug('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(g.edge(e)))
drawEdge(diagram, g.edge(e), g.edge(e).relation)
})
//
diagram.attr('height', '100%');
diagram.attr('width', '100%');
diagram.attr('viewBox', '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20));
diagram.attr('height', '100%')
diagram.attr('width', '100%')
diagram.attr('viewBox', '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20))
//
//
//
//
//if(conf.useMaxWidth) {
// if(conf.useMaxWidth) {
// diagram.attr('height', '100%');
// diagram.attr('width', '100%');
// diagram.attr('style', 'max-width:' + (width) + 'px;');
//}else{
// }else{
// diagram.attr('height',height);
// diagram.attr('width', width );
//}
//diagram.attr('viewBox', (box.startx-conf.diagramMarginX) + ' -' +conf.diagramMarginY + ' ' + width + ' ' + height);
};
// }
// diagram.attr('viewBox', (box.startx-conf.diagramMarginX) + ' -' +conf.diagramMarginY + ' ' + width + ' ' + height);
}

View File

@@ -1,38 +1,37 @@
//var proxyquire = require('proxyquire');
//var newD3;
///**
// var proxyquire = require('proxyquire');
// var newD3;
/// **
// * Created by knut on 14-11-18.
// */
//
//var d3 = {
// var d3 = {
// select:function(){
// return new newD3();
// },
// selectAll:function(){
// return new newD3();
// }
//};
// };
//var classRenderer = proxyquire('./classRenderer', { '../../d3': d3 });
//var testDom = require('testdom')('<html><body><div id="tst"></div></body></html>');
var classRenderer = require('./classRenderer');
var parser = require('./parser/classDiagram').parser;
// var classRenderer = proxyquire('./classRenderer', { '../../d3': d3 });
// var testDom = require('testdom')('<html><body><div id="tst"></div></body></html>');
var classRenderer = require('./classRenderer')
var parser = require('./parser/classDiagram').parser
describe('class diagram, ', function () {
describe('when rendering a classDiagram',function() {
var conf;
beforeEach(function () {
////parser.yy = require('./classDb');
////parser.yy.clear();
////parseError = function(err, hash) {
//// log.debug('Syntax error:' + err);
//// log.debug(hash);
////};
////sq.yy.parseError = parseError;
describe('when rendering a classDiagram', function () {
var conf
beforeEach(function () {
/// /parser.yy = require('./classDb');
/// /parser.yy.clear();
/// /parseError = function(err, hash) {
/// / log.debug('Syntax error:' + err);
/// / log.debug(hash);
/// /};
/// /sq.yy.parseError = parseError;
//
//newD3 = function() {
// newD3 = function() {
// var o = {
// append: function () {
// return newD3();
@@ -60,9 +59,9 @@ describe('class diagram, ', function () {
// };
//
// return o;
//};
// };
//
//conf = {
// conf = {
// diagramMarginX:50,
// diagramMarginY:10,
// actorMargin:50,
@@ -77,37 +76,36 @@ describe('class diagram, ', function () {
// // Depending on css styling this might need adjustment
// // Prolongs the edge of the diagram downwards
// bottomMarginAdj:1
//};
//classRenderer.setConf(conf);
// };
// classRenderer.setConf(conf);
// ... add whatever browser globals your tests might need ...
//}
Object.defineProperties(window.HTMLElement.prototype, {
getBBox :{
get : function() {return {x:10,y:10,width:100,height:100}; }
},
offsetLeft: {
get: function() { return parseFloat(window.getComputedStyle(this).marginLeft) || 0; }
},
offsetTop: {
get: function() { return parseFloat(window.getComputedStyle(this).marginTop) || 0; }
},
offsetHeight: {
get: function() { return parseFloat(window.getComputedStyle(this).height) || 0; }
},
offsetWidth: {
get: function() { return parseFloat(window.getComputedStyle(this).width) || 0; }
}
});
});
it('it should handle one actor', function () {
var str = 'classDiagram\n'+
'Class01 --|> Class02';
// }
Object.defineProperties(window.HTMLElement.prototype, {
getBBox: {
get: function () { return {x: 10, y: 10, width: 100, height: 100} }
},
offsetLeft: {
get: function () { return parseFloat(window.getComputedStyle(this).marginLeft) || 0 }
},
offsetTop: {
get: function () { return parseFloat(window.getComputedStyle(this).marginTop) || 0 }
},
offsetHeight: {
get: function () { return parseFloat(window.getComputedStyle(this).height) || 0 }
},
offsetWidth: {
get: function () { return parseFloat(window.getComputedStyle(this).width) || 0 }
}
})
})
it('it should handle one actor', function () {
var str = 'classDiagram\n' +
'Class01 --|> Class02'
//classRenderer.draw(str,'tst');
// classRenderer.draw(str,'tst');
//console.log(document.body.innerHTML);
});
});
});
// console.log(document.body.innerHTML);
})
})
})

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,21 @@
/**
* Created by knut on 14-11-18.
*/
describe('when parsing an info graph it',function() {
var ex;
beforeEach(function () {
ex = require('./parser/example').parser;
ex.yy = require('./exampleDb');
});
describe('when parsing an info graph it', function () {
var ex
beforeEach(function () {
ex = require('./parser/example').parser
ex.yy = require('./exampleDb')
})
it('should handle an info definition', function () {
var str = 'info\nsay: hello';
it('should handle an info definition', function () {
var str = 'info\nsay: hello'
ex.parse(str);
});
it('should handle an showMessage statement definition', function () {
var str = 'info\nshowInfo';
ex.parse(str)
})
it('should handle an showMessage statement definition', function () {
var str = 'info\nshowInfo'
ex.parse(str);
});
});
ex.parse(str)
})
})

View File

@@ -1,29 +1,29 @@
/**
* Created by knut on 15-01-14.
*/
var Logger = require('../../logger');
var log = Logger.Log;
var Logger = require('../../logger')
var log = Logger.Log
var message = '';
var info = false;
var message = ''
var info = false
exports.setMessage = function(txt){
log.debug('Setting message to: '+txt);
message = txt;
};
exports.setMessage = function (txt) {
log.debug('Setting message to: ' + txt)
message = txt
}
exports.getMessage = function(){
return message;
};
exports.getMessage = function () {
return message
}
exports.setInfo = function(inf){
info = inf;
};
exports.setInfo = function (inf) {
info = inf
}
exports.getInfo = function(){
return info;
};
exports.getInfo = function () {
return info
}
exports.parseError = function(err,hash){
global.mermaidAPI.parseError(err,hash);
};
exports.parseError = function (err, hash) {
global.mermaidAPI.parseError(err, hash)
}

View File

@@ -1,12 +1,12 @@
/**
* Created by knut on 14-12-11.
*/
var db = require('./exampleDb');
var exampleParser = require('./parser/example.js');
var d3 = require('../../d3');
var db = require('./exampleDb')
var exampleParser = require('./parser/example.js')
var d3 = require('../../d3')
var Logger = require('../../logger');
var log = Logger.Log;
var Logger = require('../../logger')
var log = Logger.Log
// var log = new Logger.Log();
/**
@@ -15,33 +15,33 @@ var log = Logger.Log;
* @param id
*/
exports.draw = function (txt, id, ver) {
var parser;
parser = exampleParser.parser;
parser.yy = db;
log.debug('Renering example diagram');
var parser
parser = exampleParser.parser
parser.yy = db
log.debug('Renering example diagram')
// Parse the graph definition
parser.parse(txt);
parser.parse(txt)
// Fetch the default direction, use TD if none was found
var svg = d3.select('#'+id);
var svg = d3.select('#' + id)
var g = svg.append('g');
var g = svg.append('g')
g.append('text') // text label for the x axis
g.append('text') // text label for the x axis
.attr('x', 100)
.attr('y', 40)
.attr('class','version')
.attr('font-size','32px')
.attr('class', 'version')
.attr('font-size', '32px')
.style('text-anchor', 'middle')
.text('mermaid '+ ver);
.text('mermaid ' + ver)
/*
var box = exports.bounds.getBounds();
var height = box.stopy-box.starty+2*conf.diagramMarginY;
var width = box.stopx-box.startx+2*conf.diagramMarginX;*/
var width = box.stopx-box.startx+2*conf.diagramMarginX; */
svg.attr('height',100);
svg.attr('width', 400 );
//svg.attr('viewBox', '0 0 300 150');
};
svg.attr('height', 100)
svg.attr('width', 400)
// svg.attr('viewBox', '0 0 300 150');
}

View File

@@ -50,7 +50,6 @@
}
}
token location info (@$, _$, etc.): {
first_line: n,
last_line: n,
@@ -59,7 +58,6 @@
range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)
}
the parseError function receives a 'hash' object with these members for lexer and parser errors: {
text: (matched text)
token: (the produced terminal token, if any)
@@ -71,560 +69,558 @@
recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
}
*/
var parser = (function(){
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[6,9,10,12];
var parser = {trace: function trace() { },
yy: {},
symbols_: {"error":2,"start":3,"info":4,"document":5,"EOF":6,"line":7,"statement":8,"NL":9,"showInfo":10,"message":11,"say":12,"TXT":13,"$accept":0,"$end":1},
terminals_: {2:"error",4:"info",6:"EOF",9:"NL",10:"showInfo",12:"say",13:"TXT"},
productions_: [0,[3,3],[5,0],[5,2],[7,1],[7,1],[8,1],[8,1],[11,2]],
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
var parser = (function () {
var o = function (k, v, o, l) { for (o = o || {}, l = k.length; l--; o[k[l]] = v);return o }, $V0 = [6, 9, 10, 12]
var parser = {trace: function trace () { },
yy: {},
symbols_: {'error': 2, 'start': 3, 'info': 4, 'document': 5, 'EOF': 6, 'line': 7, 'statement': 8, 'NL': 9, 'showInfo': 10, 'message': 11, 'say': 12, 'TXT': 13, '$accept': 0, '$end': 1},
terminals_: {2: 'error', 4: 'info', 6: 'EOF', 9: 'NL', 10: 'showInfo', 12: 'say', 13: 'TXT'},
productions_: [0, [3, 3], [5, 0], [5, 2], [7, 1], [7, 1], [8, 1], [8, 1], [11, 2]],
performAction: function anonymous (yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
/* this == yyval */
var $0 = $$.length - 1;
switch (yystate) {
case 1:
return yy;
break;
case 4:
break;
case 6:
yy.setInfo(true);
break;
case 7:
yy.setMessage($$[$0]);
break;
case 8:
this.$ = $$[$0-1].substring(1).trim().replace(/\\n/gm, "\n");
break;
}
},
table: [{3:1,4:[1,2]},{1:[3]},o($V0,[2,2],{5:3}),{6:[1,4],7:5,8:6,9:[1,7],10:[1,8],11:9,12:[1,10]},{1:[2,1]},o($V0,[2,3]),o($V0,[2,4]),o($V0,[2,5]),o($V0,[2,6]),o($V0,[2,7]),{13:[1,11]},o($V0,[2,8])],
defaultActions: {4:[2,1]},
parseError: function parseError(str, hash) {
if (hash.recoverable) {
this.trace(str);
} else {
function _parseError (msg, hash) {
this.message = msg;
this.hash = hash;
}
_parseError.prototype = Error;
var $0 = $$.length - 1
switch (yystate) {
case 1:
return yy
break
case 4:
throw new _parseError(str, hash);
}
},
parse: function parse(input) {
var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
var args = lstack.slice.call(arguments, 1);
var lexer = Object.create(this.lexer);
var sharedState = { yy: {} };
for (var k in this.yy) {
break
case 6:
yy.setInfo(true)
break
case 7:
yy.setMessage($$[$0])
break
case 8:
this.$ = $$[$0 - 1].substring(1).trim().replace(/\\n/gm, '\n')
break
}
},
table: [{3: 1, 4: [1, 2]}, {1: [3]}, o($V0, [2, 2], {5: 3}), {6: [1, 4], 7: 5, 8: 6, 9: [1, 7], 10: [1, 8], 11: 9, 12: [1, 10]}, {1: [2, 1]}, o($V0, [2, 3]), o($V0, [2, 4]), o($V0, [2, 5]), o($V0, [2, 6]), o($V0, [2, 7]), {13: [1, 11]}, o($V0, [2, 8])],
defaultActions: {4: [2, 1]},
parseError: function parseError (str, hash) {
if (hash.recoverable) {
this.trace(str)
} else {
function _parseError (msg, hash) {
this.message = msg
this.hash = hash
}
_parseError.prototype = Error
throw new _parseError(str, hash)
}
},
parse: function parse (input) {
var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1
var args = lstack.slice.call(arguments, 1)
var lexer = Object.create(this.lexer)
var sharedState = { yy: {} }
for (var k in this.yy) {
if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
sharedState.yy[k] = this.yy[k];
sharedState.yy[k] = this.yy[k]
}
}
lexer.setInput(input, sharedState.yy);
sharedState.yy.lexer = lexer;
sharedState.yy.parser = this;
if (typeof lexer.yylloc == 'undefined') {
lexer.yylloc = {};
}
var yyloc = lexer.yylloc;
lstack.push(yyloc);
var ranges = lexer.options && lexer.options.ranges;
if (typeof sharedState.yy.parseError === 'function') {
this.parseError = sharedState.yy.parseError;
} else {
this.parseError = Object.getPrototypeOf(this).parseError;
}
function popStack(n) {
stack.length = stack.length - 2 * n;
vstack.length = vstack.length - n;
lstack.length = lstack.length - n;
}
_token_stack:
}
lexer.setInput(input, sharedState.yy)
sharedState.yy.lexer = lexer
sharedState.yy.parser = this
if (typeof lexer.yylloc === 'undefined') {
lexer.yylloc = {}
}
var yyloc = lexer.yylloc
lstack.push(yyloc)
var ranges = lexer.options && lexer.options.ranges
if (typeof sharedState.yy.parseError === 'function') {
this.parseError = sharedState.yy.parseError
} else {
this.parseError = Object.getPrototypeOf(this).parseError
}
function popStack (n) {
stack.length = stack.length - 2 * n
vstack.length = vstack.length - n
lstack.length = lstack.length - n
}
_token_stack:
var lex = function () {
var token;
token = lexer.lex() || EOF;
if (typeof token !== 'number') {
token = self.symbols_[token] || token;
}
return token;
};
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
while (true) {
state = stack[stack.length - 1];
if (this.defaultActions[state]) {
action = this.defaultActions[state];
} else {
if (symbol === null || typeof symbol == 'undefined') {
symbol = lex();
}
action = table[state] && table[state][symbol];
var token
token = lexer.lex() || EOF
if (typeof token !== 'number') {
token = self.symbols_[token] || token
}
return token
}
if (typeof action === 'undefined' || !action.length || !action[0]) {
var errStr = '';
expected = [];
for (p in table[state]) {
if (this.terminals_[p] && p > TERROR) {
expected.push('\'' + this.terminals_[p] + '\'');
}
}
if (lexer.showPosition) {
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
} else {
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
}
this.parseError(errStr, {
text: lexer.match,
token: this.terminals_[symbol] || symbol,
line: lexer.yylineno,
loc: yyloc,
expected: expected
});
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected
while (true) {
state = stack[stack.length - 1]
if (this.defaultActions[state]) {
action = this.defaultActions[state]
} else {
if (symbol === null || typeof symbol === 'undefined') {
symbol = lex()
}
action = table[state] && table[state][symbol]
}
if (typeof action === 'undefined' || !action.length || !action[0]) {
var errStr = ''
expected = []
for (p in table[state]) {
if (this.terminals_[p] && p > TERROR) {
expected.push('\'' + this.terminals_[p] + '\'')
}
}
if (lexer.showPosition) {
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''
} else {
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'')
}
this.parseError(errStr, {
text: lexer.match,
token: this.terminals_[symbol] || symbol,
line: lexer.yylineno,
loc: yyloc,
expected: expected
})
}
if (action[0] instanceof Array && action.length > 1) {
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol)
}
switch (action[0]) {
case 1:
stack.push(symbol);
vstack.push(lexer.yytext);
lstack.push(lexer.yylloc);
stack.push(action[1]);
symbol = null;
case 1:
stack.push(symbol)
vstack.push(lexer.yytext)
lstack.push(lexer.yylloc)
stack.push(action[1])
symbol = null
if (!preErrorSymbol) {
yyleng = lexer.yyleng;
yytext = lexer.yytext;
yylineno = lexer.yylineno;
yyloc = lexer.yylloc;
if (recovering > 0) {
recovering--;
}
yyleng = lexer.yyleng
yytext = lexer.yytext
yylineno = lexer.yylineno
yyloc = lexer.yylloc
if (recovering > 0) {
recovering--
}
} else {
symbol = preErrorSymbol;
preErrorSymbol = null;
symbol = preErrorSymbol
preErrorSymbol = null
}
break;
case 2:
len = this.productions_[action[1]][1];
yyval.$ = vstack[vstack.length - len];
break
case 2:
len = this.productions_[action[1]][1]
yyval.$ = vstack[vstack.length - len]
yyval._$ = {
first_line: lstack[lstack.length - (len || 1)].first_line,
last_line: lstack[lstack.length - 1].last_line,
first_column: lstack[lstack.length - (len || 1)].first_column,
last_column: lstack[lstack.length - 1].last_column
};
first_line: lstack[lstack.length - (len || 1)].first_line,
last_line: lstack[lstack.length - 1].last_line,
first_column: lstack[lstack.length - (len || 1)].first_column,
last_column: lstack[lstack.length - 1].last_column
}
if (ranges) {
yyval._$.range = [
lstack[lstack.length - (len || 1)].range[0],
lstack[lstack.length - 1].range[1]
];
yyval._$.range = [
lstack[lstack.length - (len || 1)].range[0],
lstack[lstack.length - 1].range[1]
]
}
r = this.performAction.apply(yyval, [
yytext,
yyleng,
yylineno,
sharedState.yy,
action[1],
vstack,
lstack
].concat(args));
yytext,
yyleng,
yylineno,
sharedState.yy,
action[1],
vstack,
lstack
].concat(args))
if (typeof r !== 'undefined') {
return r;
return r
}
if (len) {
stack = stack.slice(0, -1 * len * 2);
vstack = vstack.slice(0, -1 * len);
lstack = lstack.slice(0, -1 * len);
stack = stack.slice(0, -1 * len * 2)
vstack = vstack.slice(0, -1 * len)
lstack = lstack.slice(0, -1 * len)
}
stack.push(this.productions_[action[1]][0]);
vstack.push(yyval.$);
lstack.push(yyval._$);
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
stack.push(newState);
break;
case 3:
return true;
stack.push(this.productions_[action[1]][0])
vstack.push(yyval.$)
lstack.push(yyval._$)
newState = table[stack[stack.length - 2]][stack[stack.length - 1]]
stack.push(newState)
break
case 3:
return true
}
}
return true;
}};
}
return true
}}
/* generated by jison-lex 0.3.4 */
var lexer = (function(){
var lexer = ({
var lexer = (function () {
var lexer = ({
EOF:1,
EOF: 1,
parseError:function parseError(str, hash) {
parseError: function parseError (str, hash) {
if (this.yy.parser) {
this.yy.parser.parseError(str, hash);
this.yy.parser.parseError(str, hash)
} else {
throw new Error(str);
throw new Error(str)
}
},
},
// resets the lexer, sets new input
setInput:function (input, yy) {
this.yy = yy || this.yy || {};
this._input = input;
this._more = this._backtrack = this.done = false;
this.yylineno = this.yyleng = 0;
this.yytext = this.matched = this.match = '';
this.conditionStack = ['INITIAL'];
setInput: function (input, yy) {
this.yy = yy || this.yy || {}
this._input = input
this._more = this._backtrack = this.done = false
this.yylineno = this.yyleng = 0
this.yytext = this.matched = this.match = ''
this.conditionStack = ['INITIAL']
this.yylloc = {
first_line: 1,
first_column: 0,
last_line: 1,
last_column: 0
};
if (this.options.ranges) {
this.yylloc.range = [0,0];
first_line: 1,
first_column: 0,
last_line: 1,
last_column: 0
}
this.offset = 0;
return this;
},
if (this.options.ranges) {
this.yylloc.range = [0, 0]
}
this.offset = 0
return this
},
// consumes and returns one char from the input
input:function () {
var ch = this._input[0];
this.yytext += ch;
this.yyleng++;
this.offset++;
this.match += ch;
this.matched += ch;
var lines = ch.match(/(?:\r\n?|\n).*/g);
input: function () {
var ch = this._input[0]
this.yytext += ch
this.yyleng++
this.offset++
this.match += ch
this.matched += ch
var lines = ch.match(/(?:\r\n?|\n).*/g)
if (lines) {
this.yylineno++;
this.yylloc.last_line++;
this.yylineno++
this.yylloc.last_line++
} else {
this.yylloc.last_column++;
this.yylloc.last_column++
}
if (this.options.ranges) {
this.yylloc.range[1]++;
this.yylloc.range[1]++
}
this._input = this._input.slice(1);
return ch;
},
this._input = this._input.slice(1)
return ch
},
// unshifts one char (or a string) into the input
unput:function (ch) {
var len = ch.length;
var lines = ch.split(/(?:\r\n?|\n)/g);
unput: function (ch) {
var len = ch.length
var lines = ch.split(/(?:\r\n?|\n)/g)
this._input = ch + this._input;
this.yytext = this.yytext.substr(0, this.yytext.length - len);
//this.yyleng -= len;
this.offset -= len;
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
this.match = this.match.substr(0, this.match.length - 1);
this.matched = this.matched.substr(0, this.matched.length - 1);
this._input = ch + this._input
this.yytext = this.yytext.substr(0, this.yytext.length - len)
// this.yyleng -= len;
this.offset -= len
var oldLines = this.match.split(/(?:\r\n?|\n)/g)
this.match = this.match.substr(0, this.match.length - 1)
this.matched = this.matched.substr(0, this.matched.length - 1)
if (lines.length - 1) {
this.yylineno -= lines.length - 1;
this.yylineno -= lines.length - 1
}
var r = this.yylloc.range;
var r = this.yylloc.range
this.yylloc = {
first_line: this.yylloc.first_line,
last_line: this.yylineno + 1,
first_column: this.yylloc.first_column,
last_column: lines ?
(lines.length === oldLines.length ? this.yylloc.first_column : 0)
+ oldLines[oldLines.length - lines.length].length - lines[0].length :
this.yylloc.first_column - len
};
first_line: this.yylloc.first_line,
last_line: this.yylineno + 1,
first_column: this.yylloc.first_column,
last_column: lines
? (lines.length === oldLines.length ? this.yylloc.first_column : 0) +
oldLines[oldLines.length - lines.length].length - lines[0].length
: this.yylloc.first_column - len
}
if (this.options.ranges) {
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
this.yylloc.range = [r[0], r[0] + this.yyleng - len]
}
this.yyleng = this.yytext.length;
return this;
},
this.yyleng = this.yytext.length
return this
},
// When called from action, caches matched text and appends it on next action
more:function () {
this._more = true;
return this;
},
more: function () {
this._more = true
return this
},
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
reject:function () {
reject: function () {
if (this.options.backtrack_lexer) {
this._backtrack = true;
this._backtrack = true
} else {
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
text: "",
token: null,
line: this.yylineno
});
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
text: '',
token: null,
line: this.yylineno
})
}
return this;
},
return this
},
// retain first n characters of the match
less:function (n) {
this.unput(this.match.slice(n));
},
less: function (n) {
this.unput(this.match.slice(n))
},
// displays already matched input, i.e. for error messages
pastInput:function () {
var past = this.matched.substr(0, this.matched.length - this.match.length);
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
},
pastInput: function () {
var past = this.matched.substr(0, this.matched.length - this.match.length)
return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, '')
},
// displays upcoming input, i.e. for error messages
upcomingInput:function () {
var next = this.match;
upcomingInput: function () {
var next = this.match
if (next.length < 20) {
next += this._input.substr(0, 20-next.length);
next += this._input.substr(0, 20 - next.length)
}
return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
},
return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, '')
},
// displays the character position where the lexing error occurred, i.e. for error messages
showPosition:function () {
var pre = this.pastInput();
var c = new Array(pre.length + 1).join("-");
return pre + this.upcomingInput() + "\n" + c + "^";
},
showPosition: function () {
var pre = this.pastInput()
var c = new Array(pre.length + 1).join('-')
return pre + this.upcomingInput() + '\n' + c + '^'
},
// test the lexed token: return FALSE when not a match, otherwise return token
test_match:function (match, indexed_rule) {
test_match: function (match, indexed_rule) {
var token,
lines,
backup;
lines,
backup
if (this.options.backtrack_lexer) {
// save context
backup = {
yylineno: this.yylineno,
yylloc: {
first_line: this.yylloc.first_line,
last_line: this.last_line,
first_column: this.yylloc.first_column,
last_column: this.yylloc.last_column
},
yytext: this.yytext,
match: this.match,
matches: this.matches,
matched: this.matched,
yyleng: this.yyleng,
offset: this.offset,
_more: this._more,
_input: this._input,
yy: this.yy,
conditionStack: this.conditionStack.slice(0),
done: this.done
};
if (this.options.ranges) {
backup.yylloc.range = this.yylloc.range.slice(0);
}
backup = {
yylineno: this.yylineno,
yylloc: {
first_line: this.yylloc.first_line,
last_line: this.last_line,
first_column: this.yylloc.first_column,
last_column: this.yylloc.last_column
},
yytext: this.yytext,
match: this.match,
matches: this.matches,
matched: this.matched,
yyleng: this.yyleng,
offset: this.offset,
_more: this._more,
_input: this._input,
yy: this.yy,
conditionStack: this.conditionStack.slice(0),
done: this.done
}
if (this.options.ranges) {
backup.yylloc.range = this.yylloc.range.slice(0)
}
}
lines = match[0].match(/(?:\r\n?|\n).*/g);
lines = match[0].match(/(?:\r\n?|\n).*/g)
if (lines) {
this.yylineno += lines.length;
this.yylineno += lines.length
}
this.yylloc = {
first_line: this.yylloc.last_line,
last_line: this.yylineno + 1,
first_column: this.yylloc.last_column,
last_column: lines ?
lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
this.yylloc.last_column + match[0].length
};
this.yytext += match[0];
this.match += match[0];
this.matches = match;
this.yyleng = this.yytext.length;
if (this.options.ranges) {
this.yylloc.range = [this.offset, this.offset += this.yyleng];
first_line: this.yylloc.last_line,
last_line: this.yylineno + 1,
first_column: this.yylloc.last_column,
last_column: lines
? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length
: this.yylloc.last_column + match[0].length
}
this._more = false;
this._backtrack = false;
this._input = this._input.slice(match[0].length);
this.matched += match[0];
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
this.yytext += match[0]
this.match += match[0]
this.matches = match
this.yyleng = this.yytext.length
if (this.options.ranges) {
this.yylloc.range = [this.offset, this.offset += this.yyleng]
}
this._more = false
this._backtrack = false
this._input = this._input.slice(match[0].length)
this.matched += match[0]
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1])
if (this.done && this._input) {
this.done = false;
this.done = false
}
if (token) {
return token;
return token
} else if (this._backtrack) {
// recover context
for (var k in backup) {
this[k] = backup[k];
}
return false; // rule action called reject() implying the next rule should be tested instead.
for (var k in backup) {
this[k] = backup[k]
}
return false // rule action called reject() implying the next rule should be tested instead.
}
return false;
},
return false
},
// return next match in input
next:function () {
next: function () {
if (this.done) {
return this.EOF;
return this.EOF
}
if (!this._input) {
this.done = true;
this.done = true
}
var token,
match,
tempMatch,
index;
match,
tempMatch,
index
if (!this._more) {
this.yytext = '';
this.match = '';
this.yytext = ''
this.match = ''
}
var rules = this._currentRules();
var rules = this._currentRules()
for (var i = 0; i < rules.length; i++) {
tempMatch = this._input.match(this.rules[rules[i]]);
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
match = tempMatch;
index = i;
if (this.options.backtrack_lexer) {
token = this.test_match(tempMatch, rules[i]);
if (token !== false) {
return token;
} else if (this._backtrack) {
match = false;
continue; // rule action called reject() implying a rule MISmatch.
} else {
tempMatch = this._input.match(this.rules[rules[i]])
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
match = tempMatch
index = i
if (this.options.backtrack_lexer) {
token = this.test_match(tempMatch, rules[i])
if (token !== false) {
return token
} else if (this._backtrack) {
match = false
continue // rule action called reject() implying a rule MISmatch.
} else {
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
return false;
}
} else if (!this.options.flex) {
break;
}
return false
}
} else if (!this.options.flex) {
break
}
}
}
if (match) {
token = this.test_match(match, rules[index]);
if (token !== false) {
return token;
}
token = this.test_match(match, rules[index])
if (token !== false) {
return token
}
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
return false;
return false
}
if (this._input === "") {
return this.EOF;
if (this._input === '') {
return this.EOF
} else {
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
text: "",
token: null,
line: this.yylineno
});
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
text: '',
token: null,
line: this.yylineno
})
}
},
},
// return next match that has a token
lex:function lex() {
var r = this.next();
lex: function lex () {
var r = this.next()
if (r) {
return r;
return r
} else {
return this.lex();
return this.lex()
}
},
},
// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
begin:function begin(condition) {
this.conditionStack.push(condition);
},
begin: function begin (condition) {
this.conditionStack.push(condition)
},
// pop the previously active lexer condition state off the condition stack
popState:function popState() {
var n = this.conditionStack.length - 1;
popState: function popState () {
var n = this.conditionStack.length - 1
if (n > 0) {
return this.conditionStack.pop();
return this.conditionStack.pop()
} else {
return this.conditionStack[0];
return this.conditionStack[0]
}
},
},
// produce the lexer rule set which is active for the currently active lexer condition state
_currentRules:function _currentRules() {
_currentRules: function _currentRules () {
if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules
} else {
return this.conditions["INITIAL"].rules;
return this.conditions['INITIAL'].rules
}
},
},
// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
topState:function topState(n) {
n = this.conditionStack.length - 1 - Math.abs(n || 0);
topState: function topState (n) {
n = this.conditionStack.length - 1 - Math.abs(n || 0)
if (n >= 0) {
return this.conditionStack[n];
return this.conditionStack[n]
} else {
return "INITIAL";
return 'INITIAL'
}
},
},
// alias for begin(condition)
pushState:function pushState(condition) {
this.begin(condition);
},
pushState: function pushState (condition) {
this.begin(condition)
},
// return the number of states currently on the stack
stateStackSize:function stateStackSize() {
return this.conditionStack.length;
},
options: {"case-insensitive":true},
performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
stateStackSize: function stateStackSize () {
return this.conditionStack.length
},
options: {'case-insensitive': true},
performAction: function anonymous (yy, yy_, $avoiding_name_collisions, YY_START) {
// Pre-lexer code can go here
var YYSTATE=YY_START;
switch($avoiding_name_collisions) {
case 0:return 9;
break;
case 1:return 10;
break;
case 2:return 4;
break;
case 3:return 12;
break;
case 4:return 13;
break;
case 5:return 6;
break;
case 6:return 'INVALID';
break;
}
},
rules: [/^(?:[\n]+)/i,/^(?:showInfo\b)/i,/^(?:info\b)/i,/^(?:say\b)/i,/^(?::[^#\n;]+)/i,/^(?:$)/i,/^(?:.)/i],
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6],"inclusive":true}}
});
return lexer;
})();
parser.lexer = lexer;
function Parser () {
this.yy = {};
}
Parser.prototype = parser;parser.Parser = Parser;
return new Parser;
})();
var YYSTATE = YY_START
switch ($avoiding_name_collisions) {
case 0:return 9
break
case 1:return 10
break
case 2:return 4
break
case 3:return 12
break
case 4:return 13
break
case 5:return 6
break
case 6:return 'INVALID'
break
}
},
rules: [/^(?:[\n]+)/i, /^(?:showInfo\b)/i, /^(?:info\b)/i, /^(?:say\b)/i, /^(?::[^#\n;]+)/i, /^(?:$)/i, /^(?:.)/i],
conditions: {'INITIAL': {'rules': [0, 1, 2, 3, 4, 5, 6], 'inclusive': true}}
})
return lexer
})()
parser.lexer = lexer
function Parser () {
this.yy = {}
}
Parser.prototype = parser; parser.Parser = Parser
return new Parser()
})()
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
exports.parser = parser;
exports.Parser = parser.Parser;
exports.parse = function () { return parser.parse.apply(parser, arguments); };
exports.main = function commonjsMain(args) {
exports.parser = parser
exports.Parser = parser.Parser
exports.parse = function () { return parser.parse.apply(parser, arguments) }
exports.main = function commonjsMain (args) {
if (!args[1]) {
console.log('Usage: '+args[0]+' FILE');
process.exit(1);
console.log('Usage: ' + args[0] + ' FILE')
process.exit(1)
}
var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
return exports.parser.parse(source);
};
if (typeof module !== 'undefined' && require.main === module) {
exports.main(process.argv.slice(1));
var source = require('fs').readFileSync(require('path').normalize(args[1]), 'utf8')
return exports.parser.parse(source)
}
if (typeof module !== 'undefined' && require.main === module) {
exports.main(process.argv.slice(1))
}
}
}

View File

@@ -1,6 +1,6 @@
/* global window */
/*var d3;
/* var d3;
if (require) {
try {
@@ -12,4 +12,4 @@ if (!d3) {
d3 = window.d3;
}
module.exports = d3;*/
module.exports = d3; */

View File

@@ -1,18 +1,18 @@
/* global window */
var Logger = require('../../logger');
var log = Logger.Log;
var Logger = require('../../logger')
var log = Logger.Log
var dagreD3;
//log.debug('setting up dagre-d3');
var dagreD3
// log.debug('setting up dagre-d3');
if (require) {
try {
dagreD3 = require('dagre-d3');
//log.debug('Got it (dagre-d3)');
} catch (e) {log.debug('Could not load dagre-d3');}
dagreD3 = require('dagre-d3')
// log.debug('Got it (dagre-d3)');
} catch (e) { log.debug('Could not load dagre-d3') }
}
if (!dagreD3) {
dagreD3 = window.dagreD3;
dagreD3 = window.dagreD3
}
module.exports = dagreD3;
module.exports = dagreD3

View File

@@ -1,24 +1,23 @@
/**
* Created by knut on 14-12-11.
*/
var graph = require('./graphDb');
var flow = require('./parser/flow');
var dot = require('./parser/dot');
var d3 = require('../../d3');
var dagreD3 = require('./dagre-d3');
var Logger = require('../../logger');
var log = Logger.Log;
var graph = require('./graphDb')
var flow = require('./parser/flow')
var dot = require('./parser/dot')
var d3 = require('../../d3')
var dagreD3 = require('./dagre-d3')
var Logger = require('../../logger')
var log = Logger.Log
var conf = {
};
module.exports.setConf = function(cnf){
var keys = Object.keys(cnf);
var i;
for(i=0;i<keys.length;i++){
conf[keys[i]] = cnf[keys[i]];
}
};
}
module.exports.setConf = function (cnf) {
var keys = Object.keys(cnf)
var i
for (i = 0; i < keys.length; i++) {
conf[keys[i]] = cnf[keys[i]]
}
}
/**
* Function that adds the vertices found in the graph definition to the graph to be rendered.
@@ -26,124 +25,119 @@ module.exports.setConf = function(cnf){
* @param g The graph that is to be drawn.
*/
exports.addVertices = function (vert, g) {
var keys = Object.keys(vert);
var keys = Object.keys(vert)
var styleFromStyleArr = function(styleStr,arr){
var i;
var styleFromStyleArr = function (styleStr, arr) {
var i
// Create a compound style definition from the style definitions found for the node in the graph definition
for (i = 0; i < arr.length; i++) {
if (typeof arr[i] !== 'undefined') {
styleStr = styleStr + arr[i] + ';';
}
}
for (i = 0; i < arr.length; i++) {
if (typeof arr[i] !== 'undefined') {
styleStr = styleStr + arr[i] + ';'
}
}
return styleStr;
};
return styleStr
}
// Iterate through each item in the vertice object (containing all the vertices found) in the graph definition
keys.forEach(function (id) {
var vertice = vert[id];
var verticeText;
keys.forEach(function (id) {
var vertice = vert[id]
var verticeText
/**
* Variable for storing the classes for the vertice
* @type {string}
*/
var classStr = '';
var classStr = ''
//log.debug(vertice.classes);
// log.debug(vertice.classes);
if(vertice.classes.length >0){
classStr = vertice.classes.join(' ');
}
if (vertice.classes.length > 0) {
classStr = vertice.classes.join(' ')
}
/**
* Variable for storing the extracted style for the vertice
* @type {string}
*/
var style = '';
var style = ''
// Create a compound style definition from the style definitions found for the node in the graph definition
style = styleFromStyleArr(style, vertice.styles);
style = styleFromStyleArr(style, vertice.styles)
// Use vertice id as text in the box if no text is provided by the graph definition
if (typeof vertice.text === 'undefined') {
verticeText = vertice.id;
}
else {
verticeText = vertice.text;
}
if (typeof vertice.text === 'undefined') {
verticeText = vertice.id
} else {
verticeText = vertice.text
}
var labelTypeStr = ''
if (conf.htmlLabels) {
labelTypeStr = 'html'
verticeText = verticeText.replace(/fa:fa[\w\-]+/g, function (s) {
return '<i class="fa ' + s.substring(3) + '"></i>'
})
} else {
var svg_label = document.createElementNS('http://www.w3.org/2000/svg', 'text')
var rows = verticeText.split(/<br>/)
var labelTypeStr = '';
if(conf.htmlLabels) {
labelTypeStr = 'html';
verticeText = verticeText.replace(/fa:fa[\w\-]+/g,function(s){
return '<i class="fa '+ s.substring(3)+'"></i>';
});
var j = 0
for (j = 0; j < rows.length; j++) {
var tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan')
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve')
tspan.setAttribute('dy', '1em')
tspan.setAttribute('x', '1')
tspan.textContent = rows[j]
svg_label.appendChild(tspan)
}
} else {
var svg_label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
labelTypeStr = 'svg'
verticeText = svg_label
var rows = verticeText.split(/<br>/);
// verticeText = verticeText.replace(/<br\/>/g, '\n');
// labelTypeStr = 'text';
}
var j = 0;
for(j=0;j<rows.length;j++){
var tspan = document.createElementNS('http://www.w3.org/2000/svg','tspan');
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '1');
tspan.textContent = rows[j];
svg_label.appendChild(tspan);
}
labelTypeStr = 'svg';
verticeText = svg_label;
//verticeText = verticeText.replace(/<br\/>/g, '\n');
//labelTypeStr = 'text';
}
var radious = 0;
var _shape = '';
var radious = 0
var _shape = ''
// Set the shape based parameters
switch(vertice.type){
case 'round':
radious = 5;
_shape = 'rect';
break;
case 'square':
_shape = 'rect';
break;
case 'diamond':
_shape = 'question';
break;
case 'odd':
_shape = 'rect_left_inv_arrow';
break;
case 'odd_right':
_shape = 'rect_left_inv_arrow';
break;
case 'circle':
_shape = 'circle';
break;
case 'ellipse':
_shape = 'ellipse';
break;
case 'group':
_shape = 'rect';
switch (vertice.type) {
case 'round':
radious = 5
_shape = 'rect'
break
case 'square':
_shape = 'rect'
break
case 'diamond':
_shape = 'question'
break
case 'odd':
_shape = 'rect_left_inv_arrow'
break
case 'odd_right':
_shape = 'rect_left_inv_arrow'
break
case 'circle':
_shape = 'circle'
break
case 'ellipse':
_shape = 'ellipse'
break
case 'group':
_shape = 'rect'
// Need to create a text node if using svg labels, see #367
verticeText = conf.htmlLabels ? '' : document.createElementNS('http://www.w3.org/2000/svg', 'text');
break;
default:
_shape = 'rect';
}
verticeText = conf.htmlLabels ? '' : document.createElementNS('http://www.w3.org/2000/svg', 'text')
break
default:
_shape = 'rect'
}
// Add the node
g.setNode(vertice.id, {labelType: labelTypeStr, shape:_shape, label: verticeText, rx: radious, ry: radious, 'class': classStr, style: style, id:vertice.id});
});
};
g.setNode(vertice.id, {labelType: labelTypeStr, shape: _shape, label: verticeText, rx: radious, ry: radious, 'class': classStr, style: style, id: vertice.id})
})
}
/**
* Add edges to graph based on parsed graph defninition
@@ -151,267 +145,260 @@ exports.addVertices = function (vert, g) {
* @param {Object} g The graph object
*/
exports.addEdges = function (edges, g) {
var cnt=0;
var defaultStyle;
if(typeof edges.defaultStyle !== 'undefined'){
defaultStyle = edges.defaultStyle.toString().replace(/,/g , ';');
}
var cnt = 0
edges.forEach(function (edge) {
cnt++;
var edgeData = {};
var defaultStyle
if (typeof edges.defaultStyle !== 'undefined') {
defaultStyle = edges.defaultStyle.toString().replace(/,/g, ';')
}
edges.forEach(function (edge) {
cnt++
var edgeData = {}
// Set link type for rendering
if(edge.type === 'arrow_open'){
edgeData.arrowhead = 'none';
}
else{
edgeData.arrowhead = 'normal';
}
if (edge.type === 'arrow_open') {
edgeData.arrowhead = 'none'
} else {
edgeData.arrowhead = 'normal'
}
var style = '';
var style = ''
if (typeof edge.style !== 'undefined') {
edge.style.forEach(function (s) {
style = style + s + ';'
})
} else {
switch (edge.stroke) {
case 'normal':
style = 'fill:none'
if (typeof defaultStyle !== 'undefined') {
style = defaultStyle
}
break
case 'dotted':
style = 'stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;'
break
case 'thick':
style = 'stroke: #333; stroke-width: 3.5px;fill:none'
break
}
}
edgeData.style = style
if(typeof edge.style !== 'undefined'){
edge.style.forEach(function(s){
style = style + s +';';
});
}
else{
switch(edge.stroke){
case 'normal':
style = 'fill:none';
if(typeof defaultStyle !== 'undefined'){
style = defaultStyle;
}
break;
case 'dotted':
style = 'stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;';
break;
case 'thick':
style = 'stroke: #333; stroke-width: 3.5px;fill:none';
break;
}
}
edgeData.style = style;
if (typeof edge.interpolate !== 'undefined') {
edgeData.lineInterpolate = edge.interpolate;
if (typeof edge.interpolate !== 'undefined') {
edgeData.lineInterpolate = edge.interpolate
} else {
if (typeof edges.defaultInterpolate !== 'undefined') {
edgeData.lineInterpolate = edges.defaultInterpolate
}
}
if (typeof edge.text === 'undefined') {
if (typeof edge.style !== 'undefined') {
edgeData.arrowheadStyle = 'fill: #333'
}
} else {
edgeData.arrowheadStyle = 'fill: #333'
if (typeof edge.style === 'undefined') {
edgeData.labelpos = 'c'
if (conf.htmlLabels) {
edgeData.labelType = 'html'
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>'
} else {
if (typeof edges.defaultInterpolate !== 'undefined') {
edgeData.lineInterpolate = edges.defaultInterpolate;
}
}
if (typeof edge.text === 'undefined') {
if (typeof edge.style !== 'undefined') {
edgeData.arrowheadStyle = 'fill: #333';
}
} else {
edgeData.arrowheadStyle = 'fill: #333';
if(typeof edge.style === 'undefined') {
edgeData.labelpos = 'c';
if (conf.htmlLabels) {
edgeData.labelType = 'html';
edgeData.label = '<span class="edgeLabel">'+edge.text+'</span>';
} else {
edgeData.labelType = 'text';
edgeData.style = 'stroke: #333; stroke-width: 1.5px;fill:none';
edgeData.label = edge.text.replace(/<br>/g, '\n');
}
} else {
edgeData.label = edge.text.replace(/<br>/g, '\n');
}
edgeData.labelType = 'text'
edgeData.style = 'stroke: #333; stroke-width: 1.5px;fill:none'
edgeData.label = edge.text.replace(/<br>/g, '\n')
}
} else {
edgeData.label = edge.text.replace(/<br>/g, '\n')
}
}
// Add the edge to the graph
g.setEdge(edge.start, edge.end, edgeData, cnt);
});
};
g.setEdge(edge.start, edge.end, edgeData, cnt)
})
}
/**
* Returns the all the styles from classDef statements in the graph definition.
* @returns {object} classDef styles
*/
exports.getClasses = function (text, isDot) {
var parser;
graph.clear();
if(isDot){
parser = dot.parser;
}else{
parser = flow.parser;
}
parser.yy = graph;
var parser
graph.clear()
if (isDot) {
parser = dot.parser
} else {
parser = flow.parser
}
parser.yy = graph
// Parse the graph definition
parser.parse(text);
parser.parse(text)
var classes = graph.getClasses();
var classes = graph.getClasses()
// Add default class if undefined
if(typeof(classes.default) === 'undefined') {
classes.default = {id:'default'};
//classes.default.styles = ['fill:#ffa','stroke:#666','stroke-width:3px'];
classes.default.styles = [];
classes.default.clusterStyles = ['rx:4px','fill: rgb(255, 255, 222)','rx: 4px','stroke: rgb(170, 170, 51)','stroke-width: 1px'];
classes.default.nodeLabelStyles = ['fill:#000','stroke:none','font-weight:300','font-family:"Helvetica Neue",Helvetica,Arial,sans-serf','font-size:14px'];
classes.default.edgeLabelStyles = ['fill:#000','stroke:none','font-weight:300','font-family:"Helvetica Neue",Helvetica,Arial,sans-serf','font-size:14px'];
}
return classes;
};
if (typeof (classes.default) === 'undefined') {
classes.default = {id: 'default'}
// classes.default.styles = ['fill:#ffa','stroke:#666','stroke-width:3px'];
classes.default.styles = []
classes.default.clusterStyles = ['rx:4px', 'fill: rgb(255, 255, 222)', 'rx: 4px', 'stroke: rgb(170, 170, 51)', 'stroke-width: 1px']
classes.default.nodeLabelStyles = ['fill:#000', 'stroke:none', 'font-weight:300', 'font-family:"Helvetica Neue",Helvetica,Arial,sans-serf', 'font-size:14px']
classes.default.edgeLabelStyles = ['fill:#000', 'stroke:none', 'font-weight:300', 'font-family:"Helvetica Neue",Helvetica,Arial,sans-serf', 'font-size:14px']
}
return classes
}
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
* @param text
* @param id
*/
exports.draw = function (text, id,isDot) {
log.debug('Drawing flowchart');
var parser;
graph.clear();
if(isDot){
parser = dot.parser;
}else{
parser = flow.parser;
}
parser.yy = graph;
exports.draw = function (text, id, isDot) {
log.debug('Drawing flowchart')
var parser
graph.clear()
if (isDot) {
parser = dot.parser
} else {
parser = flow.parser
}
parser.yy = graph
// Parse the graph definition
try{
parser.parse(text);
}
catch(err){
log.debug('Parsing failed');
}
try {
parser.parse(text)
} catch (err) {
log.debug('Parsing failed')
}
// Fetch the default direction, use TD if none was found
var dir;
dir = graph.getDirection();
if(typeof dir === 'undefined'){
dir='TD';
}
var dir
dir = graph.getDirection()
if (typeof dir === 'undefined') {
dir = 'TD'
}
// Create the input mermaid.graph
var g = new dagreD3.graphlib.Graph({
multigraph:true,
compound: true
})
var g = new dagreD3.graphlib.Graph({
multigraph: true,
compound: true
})
.setGraph({
rankdir: dir,
marginx: 20,
marginy: 20
rankdir: dir,
marginx: 20,
marginy: 20
})
.setDefaultEdgeLabel(function () {
return {};
});
return {}
})
var subG;
var subGraphs = graph.getSubGraphs();
var i = 0;
for(i=subGraphs.length-1;i>=0;i--){
subG = subGraphs[i];
graph.addVertex(subG.id,subG.title,'group',undefined);
}
var subG
var subGraphs = graph.getSubGraphs()
var i = 0
for (i = subGraphs.length - 1; i >= 0; i--) {
subG = subGraphs[i]
graph.addVertex(subG.id, subG.title, 'group', undefined)
}
// Fetch the verices/nodes and edges/links from the parsed graph definition
var vert = graph.getVertices();
var vert = graph.getVertices()
//log.debug(vert);
var edges = graph.getEdges();
// log.debug(vert);
var edges = graph.getEdges()
i = 0;
var j;
for(i=subGraphs.length-1;i>=0;i--){
subG = subGraphs[i];
i = 0
var j
for (i = subGraphs.length - 1; i >= 0; i--) {
subG = subGraphs[i]
d3.selectAll('cluster').append('text');
d3.selectAll('cluster').append('text')
for(j=0;j<subG.nodes.length;j++){
//log.debug('Setting node',subG.nodes[j],' to subgraph '+id);
g.setParent(subG.nodes[j],subG.id);
}
for (j = 0; j < subG.nodes.length; j++) {
// log.debug('Setting node',subG.nodes[j],' to subgraph '+id);
g.setParent(subG.nodes[j], subG.id)
}
exports.addVertices(vert, g);
exports.addEdges(edges, g);
}
exports.addVertices(vert, g)
exports.addEdges(edges, g)
// Create the renderer
var render = new dagreD3.render();
var render = new dagreD3.render()
// Add custom shape for rhombus type of boc (decision)
render.shapes().question = function (parent, bbox, node) {
var w = bbox.width,
h = bbox.height,
s = (w + h) * 0.8,
points = [
render.shapes().question = function (parent, bbox, node) {
var w = bbox.width,
h = bbox.height,
s = (w + h) * 0.8,
points = [
{x: s / 2, y: 0},
{x: s, y: -s / 2},
{x: s / 2, y: -s},
{x: 0, y: -s / 2}
];
var shapeSvg = parent.insert('polygon', ':first-child')
]
var shapeSvg = parent.insert('polygon', ':first-child')
.attr('points', points.map(function (d) {
return d.x + ',' + d.y;
return d.x + ',' + d.y
}).join(' '))
.attr('rx', 5)
.attr('ry', 5)
.attr('transform', 'translate(' + (-s / 2) + ',' + (s * 2 / 4) + ')');
node.intersect = function (point) {
return dagreD3.intersect.polygon(node, points, point);
};
return shapeSvg;
};
.attr('transform', 'translate(' + (-s / 2) + ',' + (s * 2 / 4) + ')')
node.intersect = function (point) {
return dagreD3.intersect.polygon(node, points, point)
}
return shapeSvg
}
// Add custom shape for box with inverted arrow on left side
render.shapes().rect_left_inv_arrow = function (parent, bbox, node) {
var w = bbox.width,
h = bbox.height,
points = [
{x: -h/2, y: 0},
render.shapes().rect_left_inv_arrow = function (parent, bbox, node) {
var w = bbox.width,
h = bbox.height,
points = [
{x: -h / 2, y: 0},
{x: w, y: 0},
{x: w, y: -h},
{x: -h/2, y: -h},
{x: 0, y: -h/2}
];
var shapeSvg = parent.insert('polygon', ':first-child')
{x: -h / 2, y: -h},
{x: 0, y: -h / 2}
]
var shapeSvg = parent.insert('polygon', ':first-child')
.attr('points', points.map(function (d) {
return d.x + ',' + d.y;
return d.x + ',' + d.y
}).join(' '))
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')');
node.intersect = function (point) {
return dagreD3.intersect.polygon(node, points, point);
};
return shapeSvg;
};
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')')
node.intersect = function (point) {
return dagreD3.intersect.polygon(node, points, point)
}
return shapeSvg
}
// Add custom shape for box with inverted arrow on right side
render.shapes().rect_right_inv_arrow = function (parent, bbox, node) {
var w = bbox.width,
h = bbox.height,
points = [
render.shapes().rect_right_inv_arrow = function (parent, bbox, node) {
var w = bbox.width,
h = bbox.height,
points = [
{x: 0, y: 0},
{x: w+h/2, y: 0},
{x: w, y: -h/2},
{x: w+h/2, y: -h},
{x: w + h / 2, y: 0},
{x: w, y: -h / 2},
{x: w + h / 2, y: -h},
{x: 0, y: -h}
];
var shapeSvg = parent.insert('polygon', ':first-child')
]
var shapeSvg = parent.insert('polygon', ':first-child')
.attr('points', points.map(function (d) {
return d.x + ',' + d.y;
return d.x + ',' + d.y
}).join(' '))
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')');
node.intersect = function (point) {
return dagreD3.intersect.polygon(node, points, point);
};
return shapeSvg;
};
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')')
node.intersect = function (point) {
return dagreD3.intersect.polygon(node, points, point)
}
return shapeSvg
}
// Add our custom arrow - an empty arrowhead
render.arrows().none = function normal(parent, id, edge, type) {
var marker = parent.append('marker')
render.arrows().none = function normal (parent, id, edge, type) {
var marker = parent.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
@@ -419,45 +406,45 @@ exports.draw = function (text, id,isDot) {
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
.attr('orient', 'auto')
var path = marker.append('path')
.attr('d', 'M 0 0 L 0 0 L 0 0 z');
dagreD3.util.applyStyle(path, edge[type + 'Style']);
};
var path = marker.append('path')
.attr('d', 'M 0 0 L 0 0 L 0 0 z')
dagreD3.util.applyStyle(path, edge[type + 'Style'])
}
// Override normal arrowhead defined in d3. Remove style & add class to allow css styling.
render.arrows().normal = function normal(parent, id, edge, type) {
var marker = parent.append("marker")
.attr("id", id)
.attr("viewBox", "0 0 10 10")
.attr("refX", 9)
.attr("refY", 5)
.attr("markerUnits", "strokeWidth")
.attr("markerWidth", 8)
.attr("markerHeight", 6)
.attr("orient", "auto")
render.arrows().normal = function normal (parent, id, edge, type) {
var marker = parent.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto')
var path = marker.append("path")
.attr("d", "M 0 0 L 10 5 L 0 10 z")
.attr("class", "arrowheadPath")
.style("stroke-width", 1)
.style("stroke-dasharray", "1,0");
};
var path = marker.append('path')
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
.attr('class', 'arrowheadPath')
.style('stroke-width', 1)
.style('stroke-dasharray', '1,0')
}
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select('#' + id);
//svgGroup = d3.select('#' + id + ' g');
var svg = d3.select('#' + id)
// svgGroup = d3.select('#' + id + ' g');
// Run the renderer. This is what draws the final graph.
var element = d3.select('#' + id + ' g');
render(element, g);
var element = d3.select('#' + id + ' g')
render(element, g)
//var tip = d3.tip().html(function(d) { return d; });
element.selectAll('g.node')
.attr('title', function(){
return graph.getTooltip(this.id);
});
// var tip = d3.tip().html(function(d) { return d; });
element.selectAll('g.node')
.attr('title', function () {
return graph.getTooltip(this.id)
})
/*
var xPos = document.querySelectorAll('.clusters rect')[0].x.baseVal.value;
@@ -471,79 +458,75 @@ exports.draw = function (text, id,isDot) {
te.style('text-anchor', 'middle');
te.text('Title for cluster');
*/
if(conf.useMaxWidth) {
if (conf.useMaxWidth) {
// Center the graph
svg.attr('height', '100%');
svg.attr('width', conf.width);
//svg.attr('viewBox', svgb.getBBox().x + ' 0 '+ g.graph().width+' '+ g.graph().height);
svg.attr('viewBox', '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20));
svg.attr('style', 'max-width:' + (g.graph().width + 20) + 'px;');
svg.attr('height', '100%')
svg.attr('width', conf.width)
// svg.attr('viewBox', svgb.getBBox().x + ' 0 '+ g.graph().width+' '+ g.graph().height);
svg.attr('viewBox', '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20))
svg.attr('style', 'max-width:' + (g.graph().width + 20) + 'px;')
} else {
// Center the graph
svg.attr('height', g.graph().height)
if (typeof conf.width === 'undefined') {
svg.attr('width', g.graph().width)
} else {
svg.attr('width', conf.width)
}
else{
// Center the graph
svg.attr('height', g.graph().height );
if(typeof conf.width === 'undefined'){
svg.attr('width', g.graph().width );
}else{
svg.attr('width', conf.width );
}
//svg.attr('viewBox', svgb.getBBox().x + ' 0 '+ g.graph().width+' '+ g.graph().height);
svg.attr('viewBox', '0 0 ' + (g.graph().width+20) + ' ' + (g.graph().height+20)); }
// svg.attr('viewBox', svgb.getBBox().x + ' 0 '+ g.graph().width+' '+ g.graph().height);
svg.attr('viewBox', '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20))
}
// Index nodes
graph.indexNodes('subGraph'+i);
for(i=0;i<subGraphs.length;i++){
subG = subGraphs[i];
graph.indexNodes('subGraph' + i)
if (subG.title !== 'undefined') {
var clusterRects = document.querySelectorAll('#' + id + ' #' + subG.id + ' rect');
//log.debug('looking up: #' + id + ' #' + subG.id)
var clusterEl = document.querySelectorAll('#' + id + ' #' + subG.id);
for (i = 0; i < subGraphs.length; i++) {
subG = subGraphs[i]
var xPos = clusterRects[0].x.baseVal.value;
var yPos = clusterRects[0].y.baseVal.value;
var width = clusterRects[0].width.baseVal.value;
var cluster = d3.select(clusterEl[0]);
var te = cluster.append('text');
te.attr('x', xPos + width / 2);
te.attr('y', yPos + 14);
te.attr('fill', 'black');
te.attr('stroke', 'none');
te.attr('id', id + 'Text');
te.style('text-anchor', 'middle');
if (subG.title !== 'undefined') {
var clusterRects = document.querySelectorAll('#' + id + ' #' + subG.id + ' rect')
// log.debug('looking up: #' + id + ' #' + subG.id)
var clusterEl = document.querySelectorAll('#' + id + ' #' + subG.id)
if(typeof subG.title === 'undefined'){
te.text('Undef');
}else{
//te.text(subGraphs[subGraphs.length-i-1].title);
te.text(subG.title);
var xPos = clusterRects[0].x.baseVal.value
var yPos = clusterRects[0].y.baseVal.value
var width = clusterRects[0].width.baseVal.value
var cluster = d3.select(clusterEl[0])
var te = cluster.append('text')
te.attr('x', xPos + width / 2)
te.attr('y', yPos + 14)
te.attr('fill', 'black')
te.attr('stroke', 'none')
te.attr('id', id + 'Text')
te.style('text-anchor', 'middle')
}
}
if (typeof subG.title === 'undefined') {
te.text('Undef')
} else {
// te.text(subGraphs[subGraphs.length-i-1].title);
te.text(subG.title)
}
}
}
// Add label rects for non html labels
if(!conf.htmlLabels){
var labels = document.querySelectorAll('#' + id +' .edgeLabel .label');
var i;
for(i=0;i<labels.length;i++){
var label = labels[i];
if (!conf.htmlLabels) {
var labels = document.querySelectorAll('#' + id + ' .edgeLabel .label')
var i
for (i = 0; i < labels.length; i++) {
var label = labels[i]
// Get dimensions of label
var dim = label.getBBox();
var dim = label.getBBox()
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttribute('rx',0);
rect.setAttribute('ry',0);
rect.setAttribute('width',dim.width);
rect.setAttribute('height',dim.height);
rect.setAttribute('style','fill:#e8e8e8;');
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('rx', 0)
rect.setAttribute('ry', 0)
rect.setAttribute('width', dim.width)
rect.setAttribute('height', dim.height)
rect.setAttribute('style', 'fill:#e8e8e8;')
label.insertBefore(rect, label.firstChild);
}
label.insertBefore(rect, label.firstChild)
}
};
}
}

View File

@@ -1,20 +1,20 @@
/**
* Created by knut on 14-11-03.
*/
var Logger = require('../../logger');
var log = Logger.Log;
var utils = require('../../utils');
var Logger = require('../../logger')
var log = Logger.Log
var utils = require('../../utils')
var d3 = require('../../d3');
var vertices = {};
var edges = [];
var classes = [];
var subGraphs = [];
var tooltips = {};
var subCount=0;
var direction;
var d3 = require('../../d3')
var vertices = {}
var edges = []
var classes = []
var subGraphs = []
var tooltips = {}
var subCount = 0
var direction
// Functions to be run after graph rendering
var funs = [];
var funs = []
/**
* Function called by parser when a node definition has been found
* @param id
@@ -23,42 +23,42 @@ var funs = [];
* @param style
*/
exports.addVertex = function (id, text, type, style) {
var txt;
if(typeof id === 'undefined'){
return;
}
if(id.trim().length === 0){
return;
}
var txt
if (typeof id === 'undefined') {
return
}
if (id.trim().length === 0) {
return
}
if (typeof vertices[id] === 'undefined') {
vertices[id] = {id: id, styles: [], classes: []}
}
if (typeof text !== 'undefined') {
txt = text.trim()
if (typeof vertices[id] === 'undefined') {
vertices[id] = {id: id, styles: [], classes:[]};
}
if (typeof text !== 'undefined') {
txt = text.trim();
// strip quotes if string starts and exnds with a quote
if(txt[0] === '"' && txt[txt.length-1] === '"'){
txt = txt.substring(1,txt.length-1);
}
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
txt = txt.substring(1, txt.length - 1)
}
vertices[id].text = txt;
vertices[id].text = txt
}
if (typeof type !== 'undefined') {
vertices[id].type = type
}
if (typeof type !== 'undefined') {
vertices[id].type = type
}
if (typeof style !== 'undefined') {
if (style !== null) {
style.forEach(function (s) {
vertices[id].styles.push(s)
})
}
if (typeof type !== 'undefined') {
vertices[id].type = type;
}
if (typeof type !== 'undefined') {
vertices[id].type = type;
}
if (typeof style !== 'undefined') {
if (style !== null) {
style.forEach(function (s) {
vertices[id].styles.push(s);
});
}
}
};
}
}
/**
* Function called by parser when a link/edge definition has been found
@@ -68,25 +68,25 @@ exports.addVertex = function (id, text, type, style) {
* @param linktext
*/
exports.addLink = function (start, end, type, linktext) {
log.info('Got edge...', start, end);
var edge = {start: start, end: end, type: undefined, text: ''};
linktext = type.text;
log.info('Got edge...', start, end)
var edge = {start: start, end: end, type: undefined, text: ''}
linktext = type.text
if (typeof linktext !== 'undefined') {
edge.text = linktext.trim()
if (typeof linktext !== 'undefined') {
edge.text = linktext.trim();
// strip quotes if string starts and exnds with a quote
if(edge.text[0] === '"' && edge.text[edge.text.length-1] === '"'){
edge.text = edge.text.substring(1,edge.text.length-1);
}
if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') {
edge.text = edge.text.substring(1, edge.text.length - 1)
}
}
if (typeof type !== 'undefined') {
edge.type = type.type;
edge.stroke = type.stroke;
}
edges.push(edge);
};
if (typeof type !== 'undefined') {
edge.type = type.type
edge.stroke = type.stroke
}
edges.push(edge)
}
/**
* Updates a link's line interpolation algorithm
@@ -94,12 +94,12 @@ exports.addLink = function (start, end, type, linktext) {
* @param interpolate
*/
exports.updateLinkInterpolate = function (pos, interp) {
if(pos === 'default'){
edges.defaultInterpolate = interp;
}else{
edges[pos].interpolate = interp;
}
};
if (pos === 'default') {
edges.defaultInterpolate = interp
} else {
edges[pos].interpolate = interp
}
}
/**
* Updates a link with a style
@@ -107,315 +107,304 @@ exports.updateLinkInterpolate = function (pos, interp) {
* @param style
*/
exports.updateLink = function (pos, style) {
if(pos === 'default'){
edges.defaultStyle = style;
}else{
if(utils.isSubstringInArray('fill', style) === -1) {
style.push('fill:none');
}
edges[pos].style = style;
if (pos === 'default') {
edges.defaultStyle = style
} else {
if (utils.isSubstringInArray('fill', style) === -1) {
style.push('fill:none')
}
};
edges[pos].style = style
}
}
exports.addClass = function (id, style) {
if (typeof classes[id] === 'undefined') {
classes[id] = {id: id, styles: []};
}
if (typeof classes[id] === 'undefined') {
classes[id] = {id: id, styles: []}
}
if (typeof style !== 'undefined') {
if (style !== null) {
style.forEach(function (s) {
classes[id].styles.push(s);
});
}
if (typeof style !== 'undefined') {
if (style !== null) {
style.forEach(function (s) {
classes[id].styles.push(s)
})
}
};
}
}
/**
* Called by parser when a graph definition is found, stores the direction of the chart.
* @param dir
*/
exports.setDirection = function (dir) {
direction = dir;
};
direction = dir
}
/**
* Called by parser when a graph definition is found, stores the direction of the chart.
* @param dir
*/
exports.setClass = function (id,className) {
if(id.indexOf(',')>0){
id.split(',').forEach(function(id2){
if(typeof vertices[id2] !== 'undefined'){
vertices[id2].classes.push(className);
}
});
}else{
if(typeof vertices[id] !== 'undefined'){
vertices[id].classes.push(className);
}
}
};
var setTooltip = function(id,tooltip){
if(typeof tooltip !== 'undefined'){
tooltips[id]=tooltip;
}
};
var setClickFun = function(id, functionName){
if(typeof functionName === 'undefined'){
return;
}
exports.setClass = function (id, className) {
if (id.indexOf(',') > 0) {
id.split(',').forEach(function (id2) {
if (typeof vertices[id2] !== 'undefined') {
vertices[id2].classes.push(className)
}
})
} else {
if (typeof vertices[id] !== 'undefined') {
funs.push(function (element) {
var elem = d3.select(element).select('#'+id);
if (elem !== null) {
elem.on('click', function () {
eval(functionName + '(\'' + id + '\')'); // jshint ignore:line
});
}
});
vertices[id].classes.push(className)
}
};
}
}
var setLink = function(id, linkStr){
if(typeof linkStr === 'undefined'){
return;
}
if (typeof vertices[id] !== 'undefined') {
funs.push(function (element) {
var elem = d3.select(element).select('#'+id);
if (elem !== null) {
elem.on('click', function () {
window.open(linkStr,'newTab'); // jshint ignore:line
});
}
});
}
};
exports.getTooltip = function(id){
return tooltips[id];
};
var setTooltip = function (id, tooltip) {
if (typeof tooltip !== 'undefined') {
tooltips[id] = tooltip
}
}
var setClickFun = function (id, functionName) {
if (typeof functionName === 'undefined') {
return
}
if (typeof vertices[id] !== 'undefined') {
funs.push(function (element) {
var elem = d3.select(element).select('#' + id)
if (elem !== null) {
elem.on('click', function () {
eval(functionName + '(\'' + id + '\')') // jshint ignore:line
})
}
})
}
}
var setLink = function (id, linkStr) {
if (typeof linkStr === 'undefined') {
return
}
if (typeof vertices[id] !== 'undefined') {
funs.push(function (element) {
var elem = d3.select(element).select('#' + id)
if (elem !== null) {
elem.on('click', function () {
window.open(linkStr, 'newTab') // jshint ignore:line
})
}
})
}
}
exports.getTooltip = function (id) {
return tooltips[id]
}
/**
* Called by parser when a graph definition is found, stores the direction of the chart.
* @param dir
*/
exports.setClickEvent = function (id,functionName, link,tooltip) {
if(id.indexOf(',')>0){
id.split(',').forEach(function(id2) {
setTooltip(id2,tooltip);
setClickFun(id2, functionName);
setLink(id2, link);
});
}else{
setTooltip(id,tooltip);
setClickFun(id, functionName);
setLink(id, link);
}
};
exports.setClickEvent = function (id, functionName, link, tooltip) {
if (id.indexOf(',') > 0) {
id.split(',').forEach(function (id2) {
setTooltip(id2, tooltip)
setClickFun(id2, functionName)
setLink(id2, link)
})
} else {
setTooltip(id, tooltip)
setClickFun(id, functionName)
setLink(id, link)
}
}
exports.bindFunctions = function(element){
funs.forEach(function(fun){
fun(element);
});
};
exports.bindFunctions = function (element) {
funs.forEach(function (fun) {
fun(element)
})
}
exports.getDirection = function () {
return direction;
};
return direction
}
/**
* Retrieval function for fetching the found nodes after parsing has completed.
* @returns {{}|*|vertices}
*/
exports.getVertices = function () {
return vertices;
};
return vertices
}
/**
* Retrieval function for fetching the found links after parsing has completed.
* @returns {{}|*|edges}
*/
exports.getEdges = function () {
return edges;
};
return edges
}
/**
* Retrieval function for fetching the found class definitions after parsing has completed.
* @returns {{}|*|classes}
*/
exports.getClasses = function () {
return classes;
};
return classes
}
var setupToolTips = function(element){
var tooltipElem = d3.select('.mermaidTooltip');
if(tooltipElem[0][0] === null){
tooltipElem = d3.select('body')
var setupToolTips = function (element) {
var tooltipElem = d3.select('.mermaidTooltip')
if (tooltipElem[0][0] === null) {
tooltipElem = d3.select('body')
.append('div')
.attr('class', 'mermaidTooltip')
.style('opacity', 0);
}
.style('opacity', 0)
}
var svg = d3.select(element).select('svg');
var svg = d3.select(element).select('svg')
var nodes = svg.selectAll('g.node');
nodes
.on('mouseover', function() {
var el = d3.select(this);
var title = el.attr('title');
var nodes = svg.selectAll('g.node')
nodes
.on('mouseover', function () {
var el = d3.select(this)
var title = el.attr('title')
// Dont try to draw a tooltip if no data is provided
if(title === null){
return;
}
var rect = this.getBoundingClientRect();
if (title === null) {
return
}
var rect = this.getBoundingClientRect()
tooltipElem.transition()
tooltipElem.transition()
.duration(200)
.style('opacity', '.9');
tooltipElem.html(el.attr('title'))
.style('left', (rect.left+(rect.right-rect.left)/2) + 'px')
.style('top', (rect.top-14+document.body.scrollTop) + 'px');
el.classed('hover',true);
.style('opacity', '.9')
tooltipElem.html(el.attr('title'))
.style('left', (rect.left + (rect.right - rect.left) / 2) + 'px')
.style('top', (rect.top - 14 + document.body.scrollTop) + 'px')
el.classed('hover', true)
})
.on('mouseout', function() {
tooltipElem.transition()
.on('mouseout', function () {
tooltipElem.transition()
.duration(500)
.style('opacity', 0);
var el = d3.select(this);
el.classed('hover',false);
});
};
funs.push(setupToolTips);
.style('opacity', 0)
var el = d3.select(this)
el.classed('hover', false)
})
}
funs.push(setupToolTips)
/**
* Clears the internal graph db so that a new graph can be parsed.
*/
exports.clear = function () {
vertices = {};
classes = {};
edges = [];
funs = [];
funs.push(setupToolTips);
subGraphs = [];
subCount = 0;
tooltips = [];
};
vertices = {}
classes = {}
edges = []
funs = []
funs.push(setupToolTips)
subGraphs = []
subCount = 0
tooltips = []
}
/**
*
* @returns {string}
*/
exports.defaultStyle = function () {
return 'fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;';
};
return 'fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;'
}
/**
* Clears the internal graph db so that a new graph can be parsed.
*/
exports.addSubGraph = function (list, title) {
function uniq(a) {
var prims = {'boolean':{}, 'number':{}, 'string':{}}, objs = [];
function uniq (a) {
var prims = {'boolean': {}, 'number': {}, 'string': {}}, objs = []
return a.filter(function(item) {
var type = typeof item;
if(item===' '){
return false;
}
if(type in prims)
return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
else
return objs.indexOf(item) >= 0 ? false : objs.push(item);
});
return a.filter(function (item) {
var type = typeof item
if (item === ' ') {
return false
}
if (type in prims) { return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true) } else { return objs.indexOf(item) >= 0 ? false : objs.push(item) }
})
}
var nodeList = []
nodeList = uniq(nodeList.concat.apply(nodeList, list))
var subGraph = {id: 'subGraph' + subCount, nodes: nodeList, title: title}
// log.debug('subGraph:' + subGraph.title + subGraph.id);
// log.debug(subGraph.nodes);
subGraphs.push(subGraph)
subCount = subCount + 1
return subGraph.id
}
var getPosForId = function (id) {
var i
for (i = 0; i < subGraphs.length; i++) {
if (subGraphs[i].id === id) {
// log.debug('Found pos for ',id,' ',i);
return i
}
var nodeList = [];
nodeList = uniq(nodeList.concat.apply(nodeList,list));
var subGraph = {id:'subGraph'+subCount, nodes:nodeList,title:title};
//log.debug('subGraph:' + subGraph.title + subGraph.id);
//log.debug(subGraph.nodes);
subGraphs.push(subGraph);
subCount = subCount + 1;
return subGraph.id;
};
var getPosForId = function(id){
var i;
for(i=0;i<subGraphs.length;i++){
if(subGraphs[i].id===id){
//log.debug('Found pos for ',id,' ',i);
return i;
}
}
//log.debug('No pos found for ',id,' ',i);
return -1;
};
var secCount = -1;
var posCrossRef = [];
}
// log.debug('No pos found for ',id,' ',i);
return -1
}
var secCount = -1
var posCrossRef = []
var indexNodes = function (id, pos) {
var nodes = subGraphs[pos].nodes;
secCount = secCount + 1;
if(secCount>2000){
return;
}
//var nPos = getPosForId(subGraphs[pos].id);
posCrossRef[secCount]=pos;
var nodes = subGraphs[pos].nodes
secCount = secCount + 1
if (secCount > 2000) {
return
}
// var nPos = getPosForId(subGraphs[pos].id);
posCrossRef[secCount] = pos
// Check if match
if(subGraphs[pos].id === id){
return {
result:true,
count:0
};
}
var count = 0;
var posCount = 1;
while(count<nodes.length){
var childPos = getPosForId(nodes[count]);
// Ignore regular nodes (pos will be -1)
if(childPos>=0){
var res = indexNodes(id,childPos);
if(res.result){
return {
result:true,
count:posCount+res.count
};
}else{
posCount = posCount + res.count;
}
}
count = count +1;
}
if (subGraphs[pos].id === id) {
return {
result:false,
count:posCount
};
};
result: true,
count: 0
}
}
var count = 0
var posCount = 1
while (count < nodes.length) {
var childPos = getPosForId(nodes[count])
// Ignore regular nodes (pos will be -1)
if (childPos >= 0) {
var res = indexNodes(id, childPos)
if (res.result) {
return {
result: true,
count: posCount + res.count
}
} else {
posCount = posCount + res.count
}
}
count = count + 1
}
return {
result: false,
count: posCount
}
}
exports.getDepthFirstPos = function (pos) {
return posCrossRef[pos];
};
return posCrossRef[pos]
}
exports.indexNodes = function () {
secCount = -1;
if(subGraphs.length>0){
indexNodes('none',subGraphs.length-1,0);
}
};
secCount = -1
if (subGraphs.length > 0) {
indexNodes('none', subGraphs.length - 1, 0)
}
}
exports.getSubGraphs = function () {
return subGraphs;
};
return subGraphs
}
exports.parseError = function(err,hash){
global.mermaidAPI.parseError(err,hash);
};
exports.parseError = function (err, hash) {
global.mermaidAPI.parseError(err, hash)
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,55 +1,55 @@
/**
* Created by knut on 14-11-18.
*/
describe('when parsing a gantt diagram it',function() {
var gantt;
beforeEach(function () {
gantt = require('./parser/gantt').parser;
gantt.yy = require('./ganttDb');
describe('when parsing a gantt diagram it', function () {
var gantt
beforeEach(function () {
gantt = require('./parser/gantt').parser
gantt.yy = require('./ganttDb')
//ex.yy.parseError = parseError;
});
// ex.yy.parseError = parseError;
})
it('should handle an dateFormat definition', function () {
var str = 'gantt\ndateFormat yyyy-mm-dd';
it('should handle an dateFormat definition', function () {
var str = 'gantt\ndateFormat yyyy-mm-dd'
gantt.parse(str);
});
it('should handle an dateFormat definition', function () {
var str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid';
gantt.parse(str)
})
it('should handle an dateFormat definition', function () {
var str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid'
gantt.parse(str);
});
it('should handle an dateFormat definition', function () {
var str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid';
gantt.parse(str)
})
it('should handle an dateFormat definition', function () {
var str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid'
gantt.parse(str);
});
it('should handle an section definition', function () {
var str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid';
gantt.parse(str)
})
it('should handle an section definition', function () {
var str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid'
gantt.parse(str);
});
gantt.parse(str)
})
/**
* Beslutsflöde inligt nedan. Obs bla bla bla
* Beslutsflöde inligt nedan. Obs bla bla bla
* ```
* graph TD
* A[Hard pledge] -- text on link -->B(Round edge)
* B --> C{to do or not to do}
* C -->|Too| D[Result one]
* C -->|Doo| E[Result two]
```
```
* params bapa - a unique bapap
*/
it('should handle a task definition', function () {
var str = 'gantt\n' +
it('should handle a task definition', function () {
var str = 'gantt\n' +
'dateFormat yyyy-mm-dd\n' +
'title Adding gantt diagram functionality to mermaid\n' +
'section Documentation\n' +
'Design jison grammar:des1, 2014-01-01, 2014-01-04';
'Design jison grammar:des1, 2014-01-01, 2014-01-04'
gantt.parse(str);
});
});
gantt.parse(str)
})
})
// Ogiltigt id i after id

View File

@@ -1,152 +1,148 @@
/**
* Created by knut on 15-01-14.
*/
var moment = require('moment');
var Logger = require('../../logger');
var log = Logger.Log;
var moment = require('moment')
var Logger = require('../../logger')
var log = Logger.Log
var dateFormat = ''
var title = ''
var sections = []
var tasks = []
var currentSection = ''
var dateFormat = '';
var title = '';
var sections = [];
var tasks = [];
var currentSection = '';
exports.clear = function () {
sections = []
tasks = []
currentSection = ''
title = ''
taskCnt = 0
lastTask = undefined
lastTaskID = undefined
rawTasks = []
}
exports.clear = function(){
sections = [];
tasks = [];
currentSection = '';
title = '';
taskCnt = 0;
lastTask = undefined;
lastTaskID = undefined;
rawTasks = [];
};
exports.setDateFormat = function (txt) {
dateFormat = txt
}
exports.setDateFormat = function(txt){
dateFormat = txt;
};
exports.getDateFormat = function () {
return dateFormat
}
exports.setTitle = function (txt) {
title = txt
}
exports.getDateFormat = function(){
return dateFormat;
};
exports.setTitle = function(txt){
title = txt;
};
exports.getTitle = function () {
return title
}
exports.getTitle = function(){
return title;
};
exports.addSection = function (txt) {
currentSection = txt
sections.push(txt)
}
exports.addSection = function(txt){
currentSection = txt;
sections.push(txt);
};
exports.getTasks = function () {
var allItemsPricessed = compileTasks()
var maxDepth = 10
var iterationCount = 0
while (!allItemsPricessed && (iterationCount < maxDepth)) {
allItemsPricessed = compileTasks()
iterationCount++
}
tasks = rawTasks
exports.getTasks=function(){
var allItemsPricessed = compileTasks();
var maxDepth = 10;
var iterationCount = 0;
while(!allItemsPricessed && (iterationCount < maxDepth)){
allItemsPricessed = compileTasks();
iterationCount++;
}
tasks = rawTasks;
//var i;
//for(i=10000;i<tasks.length;i++){
// var i;
// for(i=10000;i<tasks.length;i++){
// tasks[i].startTime = moment(tasks[i].startTime).format(dateFormat);
// tasks[i].endTime = moment(tasks[i].endTime).format(dateFormat);
//}
// }
return tasks;
};
return tasks
}
var getStartDate = function (prevTime, dateFormat, str) {
// console.log('Deciding start date:'+JSON.stringify(str));
// log.debug('Deciding start date:'+str);
// log.debug('with dateformat:'+dateFormat);
var getStartDate = function(prevTime, dateFormat, str){
//console.log('Deciding start date:'+JSON.stringify(str));
//log.debug('Deciding start date:'+str);
//log.debug('with dateformat:'+dateFormat);
str = str.trim();
str = str.trim()
// Test for after
var re = /^after\s+([\d\w\-]+)/;
var afterStatement = re.exec(str.trim());
var re = /^after\s+([\d\w\-]+)/
var afterStatement = re.exec(str.trim())
if(afterStatement!==null){
var task = exports.findTaskById(afterStatement[1]);
if (afterStatement !== null) {
var task = exports.findTaskById(afterStatement[1])
if(typeof task === 'undefined'){
var dt = new Date();
dt.setHours(0,0,0,0);
return dt;
//return undefined;
}
return task.endTime;
if (typeof task === 'undefined') {
var dt = new Date()
dt.setHours(0, 0, 0, 0)
return dt
// return undefined;
}
return task.endTime
}
// Check for actual date set
if(moment(str,dateFormat.trim(),true).isValid()){
return moment(str,dateFormat.trim(),true).toDate();
}else{
log.debug('Invalid date:'+str);
log.debug('With date format:'+dateFormat.trim());
//log.debug('----');
}
if (moment(str, dateFormat.trim(), true).isValid()) {
return moment(str, dateFormat.trim(), true).toDate()
} else {
log.debug('Invalid date:' + str)
log.debug('With date format:' + dateFormat.trim())
// log.debug('----');
}
// Default date - now
return new Date();
};
return new Date()
}
var getEndDate = function(prevTime, dateFormat, str){
str = str.trim();
var getEndDate = function (prevTime, dateFormat, str) {
str = str.trim()
// Check for actual date
if(moment(str,dateFormat.trim(),true).isValid()){
if (moment(str, dateFormat.trim(), true).isValid()) {
return moment(str, dateFormat.trim()).toDate()
}
return moment(str,dateFormat.trim()).toDate();
}
var d = moment(prevTime);
var d = moment(prevTime)
// Check for length
var re = /^([\d]+)([wdhms])/;
var durationStatement = re.exec(str.trim());
var re = /^([\d]+)([wdhms])/
var durationStatement = re.exec(str.trim())
if(durationStatement!== null){
switch(durationStatement[2]){
case 's':
d.add(durationStatement[1], 'seconds');
break;
case 'm':
d.add(durationStatement[1], 'minutes');
break;
case 'h':
d.add(durationStatement[1], 'hours');
break;
case 'd':
d.add(durationStatement[1], 'days');
break;
case 'w':
d.add(durationStatement[1], 'weeks');
break;
}
return d.toDate();
if (durationStatement !== null) {
switch (durationStatement[2]) {
case 's':
d.add(durationStatement[1], 'seconds')
break
case 'm':
d.add(durationStatement[1], 'minutes')
break
case 'h':
d.add(durationStatement[1], 'hours')
break
case 'd':
d.add(durationStatement[1], 'days')
break
case 'w':
d.add(durationStatement[1], 'weeks')
break
}
return d.toDate()
}
// Default date - now
return d.toDate();
};
return d.toDate()
}
var taskCnt = 0;
var parseId = function(idStr){
if(typeof idStr === 'undefined'){
taskCnt = taskCnt + 1;
return 'task'+taskCnt;
}
return idStr;
};
var taskCnt = 0
var parseId = function (idStr) {
if (typeof idStr === 'undefined') {
taskCnt = taskCnt + 1
return 'task' + taskCnt
}
return idStr
}
// id, startDate, endDate
// id, startDate, length
// id, after x, endDate
@@ -158,241 +154,224 @@ var parseId = function(idStr){
// endDate
// length
var compileData = function(prevTask, dataStr){
var ds;
var compileData = function (prevTask, dataStr) {
var ds
if(dataStr.substr(0,1) === ':'){
ds = dataStr.substr(1,dataStr.length);
}
else{
ds=dataStr;
}
if (dataStr.substr(0, 1) === ':') {
ds = dataStr.substr(1, dataStr.length)
} else {
ds = dataStr
}
var data = ds.split(',');
var task = {};
var df = exports.getDateFormat();
var data = ds.split(',')
var task = {}
var df = exports.getDateFormat()
// Get tags like active, done cand crit
var matchFound = true;
while(matchFound){
matchFound = false;
if(data[0].match(/^\s*active\s*$/)){
task.active = true;
data.shift(1);
matchFound = true;
}
if(data[0].match(/^\s*done\s*$/)){
task.done = true;
data.shift(1);
matchFound = true;
}
if(data[0].match(/^\s*crit\s*$/)){
task.crit = true;
data.shift(1);
matchFound = true;
}
var matchFound = true
while (matchFound) {
matchFound = false
if (data[0].match(/^\s*active\s*$/)) {
task.active = true
data.shift(1)
matchFound = true
}
var i;
for(i=0;i<data.length;i++){
data[i] = data[i].trim();
if (data[0].match(/^\s*done\s*$/)) {
task.done = true
data.shift(1)
matchFound = true
}
switch(data.length){
case 1:
task.id = parseId();
task.startTime = prevTask.endTime;
task.endTime = getEndDate(task.startTime, df, data[0]);
break;
case 2:
task.id = parseId();
task.startTime = getStartDate(undefined, df, data[0]);
task.endTime = getEndDate(task.startTime, df, data[1]);
break;
case 3:
task.id = parseId(data[0]);
task.startTime = getStartDate(undefined, df, data[1]);
task.endTime = getEndDate(task.startTime, df, data[2]);
break;
default:
if (data[0].match(/^\s*crit\s*$/)) {
task.crit = true
data.shift(1)
matchFound = true
}
}
var i
for (i = 0; i < data.length; i++) {
data[i] = data[i].trim()
}
return task;
};
switch (data.length) {
case 1:
task.id = parseId()
task.startTime = prevTask.endTime
task.endTime = getEndDate(task.startTime, df, data[0])
break
case 2:
task.id = parseId()
task.startTime = getStartDate(undefined, df, data[0])
task.endTime = getEndDate(task.startTime, df, data[1])
break
case 3:
task.id = parseId(data[0])
task.startTime = getStartDate(undefined, df, data[1])
task.endTime = getEndDate(task.startTime, df, data[2])
break
default:
}
var parseData = function(prevTaskId, dataStr){
var ds;
return task
}
if(dataStr.substr(0,1) === ':'){
ds = dataStr.substr(1,dataStr.length);
}
else{
ds=dataStr;
}
var parseData = function (prevTaskId, dataStr) {
var ds
var data = ds.split(',');
if (dataStr.substr(0, 1) === ':') {
ds = dataStr.substr(1, dataStr.length)
} else {
ds = dataStr
}
var data = ds.split(',')
var task = {};
var task = {}
// Get tags like active, done cand crit
var matchFound = true;
while(matchFound){
matchFound = false;
if(data[0].match(/^\s*active\s*$/)){
task.active = true;
data.shift(1);
matchFound = true;
}
if(data[0].match(/^\s*done\s*$/)){
task.done = true;
data.shift(1);
matchFound = true;
}
if(data[0].match(/^\s*crit\s*$/)){
task.crit = true;
data.shift(1);
matchFound = true;
}
var matchFound = true
while (matchFound) {
matchFound = false
if (data[0].match(/^\s*active\s*$/)) {
task.active = true
data.shift(1)
matchFound = true
}
var i;
for(i=0;i<data.length;i++){
data[i] = data[i].trim();
if (data[0].match(/^\s*done\s*$/)) {
task.done = true
data.shift(1)
matchFound = true
}
switch(data.length){
case 1:
task.id = parseId();
task.startTime = {type: 'prevTaskEnd', id:prevTaskId};
task.endTime = {data: data[0]};
break;
case 2:
task.id = parseId();
task.startTime = {type:'getStartDate',startData:data[0]};
task.endTime = {data: data[1]};
break;
case 3:
task.id = parseId(data[0]);
task.startTime = {type:'getStartDate',startData: data[1]};
task.endTime = {data: data[2]};
break;
default:
if (data[0].match(/^\s*crit\s*$/)) {
task.crit = true
data.shift(1)
matchFound = true
}
}
var i
for (i = 0; i < data.length; i++) {
data[i] = data[i].trim()
}
return task;
};
switch (data.length) {
case 1:
task.id = parseId()
task.startTime = {type: 'prevTaskEnd', id: prevTaskId}
task.endTime = {data: data[0]}
break
case 2:
task.id = parseId()
task.startTime = {type: 'getStartDate', startData: data[0]}
task.endTime = {data: data[1]}
break
case 3:
task.id = parseId(data[0])
task.startTime = {type: 'getStartDate', startData: data[1]}
task.endTime = {data: data[2]}
break
default:
}
return task
}
var lastTask
var lastTaskID
var rawTasks = []
var taskDb = {}
exports.addTask = function (descr, data) {
var rawTask = {
section: currentSection,
type: currentSection,
processed: false,
raw: {data: data},
task: descr
}
var taskInfo = parseData(lastTaskID, data)
rawTask.raw.startTime = taskInfo.startTime
rawTask.raw.endTime = taskInfo.endTime
rawTask.id = taskInfo.id
rawTask.prevTaskId = lastTaskID
rawTask.active = taskInfo.active
rawTask.done = taskInfo.done
rawTask.crit = taskInfo.crit
var lastTask;
var lastTaskID;
var rawTasks = [];
var taskDb = {};
exports.addTask = function(descr,data){
var rawTask = {
section:currentSection,
type:currentSection,
processed:false,
raw:{data:data},
task:descr
};
var taskInfo = parseData(lastTaskID, data);
rawTask.raw.startTime = taskInfo.startTime;
rawTask.raw.endTime = taskInfo.endTime;
rawTask.id = taskInfo.id;
rawTask.prevTaskId = lastTaskID;
rawTask.active = taskInfo.active;
rawTask.done = taskInfo.done;
rawTask.crit = taskInfo.crit;
var pos = rawTasks.push(rawTask)
var pos = rawTasks.push(rawTask);
lastTaskID = rawTask.id;
lastTaskID = rawTask.id
// Store cross ref
taskDb[rawTask.id]= pos-1;
taskDb[rawTask.id] = pos - 1
}
};
exports.findTaskById = function(id) {
//var i;
//for(i=0;i<tasks.length;i++){
exports.findTaskById = function (id) {
// var i;
// for(i=0;i<tasks.length;i++){
// if(tasks[i].id === id){
// return tasks[i];
// }
//}
// }
var pos = taskDb[id];
return rawTasks[pos];
};
var pos = taskDb[id]
return rawTasks[pos]
}
exports.addTaskOrg = function(descr,data){
exports.addTaskOrg = function (descr, data) {
var newTask = {
section: currentSection,
type: currentSection,
description: descr,
task: descr
}
var taskInfo = compileData(lastTask, data)
newTask.startTime = taskInfo.startTime
newTask.endTime = taskInfo.endTime
newTask.id = taskInfo.id
newTask.active = taskInfo.active
newTask.done = taskInfo.done
newTask.crit = taskInfo.crit
lastTask = newTask
tasks.push(newTask)
}
var newTask = {
section:currentSection,
type:currentSection,
description:descr,
task:descr
};
var taskInfo = compileData(lastTask, data);
newTask.startTime = taskInfo.startTime;
newTask.endTime = taskInfo.endTime;
newTask.id = taskInfo.id;
newTask.active = taskInfo.active;
newTask.done = taskInfo.done;
newTask.crit = taskInfo.crit;
lastTask = newTask;
tasks.push(newTask);
};
var compileTasks = function () {
var df = exports.getDateFormat()
var compileTasks=function(){
var df = exports.getDateFormat();
var compileTask = function(pos){
var task = rawTasks[pos];
var startTime = '';
switch(rawTasks[pos].raw.startTime.type){
case 'prevTaskEnd':
var prevTask = exports.findTaskById(task.prevTaskId);
task.startTime = prevTask.endTime;
break;
case 'getStartDate':
startTime = getStartDate(undefined, df, rawTasks[pos].raw.startTime.startData);
if(startTime){
rawTasks[pos].startTime = startTime;
}
break;
var compileTask = function (pos) {
var task = rawTasks[pos]
var startTime = ''
switch (rawTasks[pos].raw.startTime.type) {
case 'prevTaskEnd':
var prevTask = exports.findTaskById(task.prevTaskId)
task.startTime = prevTask.endTime
break
case 'getStartDate':
startTime = getStartDate(undefined, df, rawTasks[pos].raw.startTime.startData)
if (startTime) {
rawTasks[pos].startTime = startTime
}
if(rawTasks[pos].startTime){
rawTasks[pos].endTime = getEndDate(rawTasks[pos].startTime, df, rawTasks[pos].raw.endTime.data);
if(rawTasks[pos].endTime){
rawTasks[pos].processed = true;
}
}
return rawTasks[pos].processed;
};
var i;
var allProcessed = true;
for(i=0;i<rawTasks.length;i++){
compileTask(i);
allProcessed = allProcessed && rawTasks[i].processed;
break
}
return allProcessed;
};
exports.parseError = function(err,hash){
global.mermaidAPI.parseError(err,hash);
};
if (rawTasks[pos].startTime) {
rawTasks[pos].endTime = getEndDate(rawTasks[pos].startTime, df, rawTasks[pos].raw.endTime.data)
if (rawTasks[pos].endTime) {
rawTasks[pos].processed = true
}
}
return rawTasks[pos].processed
}
var i
var allProcessed = true
for (i = 0; i < rawTasks.length; i++) {
compileTask(i)
allProcessed = allProcessed && rawTasks[i].processed
}
return allProcessed
}
exports.parseError = function (err, hash) {
global.mermaidAPI.parseError(err, hash)
}

View File

@@ -1,184 +1,183 @@
/**
* Created by knut on 14-11-18.
*/
describe('when using the ganttDb',function() {
var gDb;
var moment = require('moment');
beforeEach(function () {
//gantt = require('./parser/gantt').parser;
describe('when using the ganttDb', function () {
var gDb
var moment = require('moment')
gDb = require('./ganttDb');
gDb.clear();
//ex.yy.parseError = parseError;
});
beforeEach(function () {
// gantt = require('./parser/gantt').parser;
it('should handle an fixed dates', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2013-01-12');
var tasks = gDb.getTasks();
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime ).toEqual(moment('2013-01-12', 'YYYY-MM-DD').toDate());
expect(tasks[0].id ).toEqual('id1');
expect(tasks[0].task).toEqual('test1');
});
it('should handle duration (days) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2d');
var tasks = gDb.getTasks();
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime ).toEqual(moment('2013-01-03', 'YYYY-MM-DD').toDate());
expect(tasks[0].id ).toEqual('id1');
expect(tasks[0].task).toEqual('test1');
});
it('should handle duration (hours) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2h');
var tasks = gDb.getTasks();
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime ).toEqual(moment('2013-01-01 2:00', 'YYYY-MM-DD hh:mm').toDate());
expect(tasks[0].id ).toEqual('id1');
expect(tasks[0].task).toEqual('test1');
});
it('should handle duration (minutes) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2m');
var tasks = gDb.getTasks();
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime ).toEqual(moment('2013-01-01 00:02', 'YYYY-MM-DD hh:mm').toDate());
expect(tasks[0].id ).toEqual('id1');
expect(tasks[0].task).toEqual('test1');
});
it('should handle duration (seconds) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2s');
var tasks = gDb.getTasks();
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime ).toEqual(moment('2013-01-01 00:00:02', 'YYYY-MM-DD hh:mm:ss').toDate());
expect(tasks[0].id ).toEqual('id1');
expect(tasks[0].task).toEqual('test1');
});
it('should handle duration (weeks) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2w');
var tasks = gDb.getTasks();
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime ).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate());
expect(tasks[0].id ).toEqual('id1');
expect(tasks[0].task).toEqual('test1');
});
it('should handle relative start date based on id', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2w');
gDb.addTask('test2','id2,after id1,1d');
var tasks = gDb.getTasks();
expect(tasks[1].startTime ).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate());
expect(tasks[1].id ).toEqual('id2');
expect(tasks[1].task).toEqual('test2');
});
it('should handle relative start date based on id when id is invalid', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2w');
gDb.addTask('test2','id2,after id3,1d');
var tasks = gDb.getTasks();
expect(tasks[1].startTime).toEqual(new Date((new Date()).setHours(0,0,0,0)));
expect(tasks[1].id ).toEqual('id2');
expect(tasks[1].task).toEqual('test2');
});
gDb = require('./ganttDb')
gDb.clear()
// ex.yy.parseError = parseError;
})
it('should handle fixed dates without id', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','2013-01-01,2013-01-12');
var tasks = gDb.getTasks();
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime ).toEqual(moment('2013-01-12', 'YYYY-MM-DD').toDate());
expect(tasks[0].id ).toEqual('task1');
expect(tasks[0].task).toEqual('test1');
});
it('should handle an fixed dates', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2013-01-12')
var tasks = gDb.getTasks()
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2013-01-12', 'YYYY-MM-DD').toDate())
expect(tasks[0].id).toEqual('id1')
expect(tasks[0].task).toEqual('test1')
})
it('should handle duration (days) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2d')
var tasks = gDb.getTasks()
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2013-01-03', 'YYYY-MM-DD').toDate())
expect(tasks[0].id).toEqual('id1')
expect(tasks[0].task).toEqual('test1')
})
it('should handle duration (hours) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2h')
var tasks = gDb.getTasks()
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2013-01-01 2:00', 'YYYY-MM-DD hh:mm').toDate())
expect(tasks[0].id).toEqual('id1')
expect(tasks[0].task).toEqual('test1')
})
it('should handle duration (minutes) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2m')
var tasks = gDb.getTasks()
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2013-01-01 00:02', 'YYYY-MM-DD hh:mm').toDate())
expect(tasks[0].id).toEqual('id1')
expect(tasks[0].task).toEqual('test1')
})
it('should handle duration (seconds) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2s')
var tasks = gDb.getTasks()
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2013-01-01 00:00:02', 'YYYY-MM-DD hh:mm:ss').toDate())
expect(tasks[0].id).toEqual('id1')
expect(tasks[0].task).toEqual('test1')
})
it('should handle duration (weeks) instead of fixed date to determine end date', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2w')
var tasks = gDb.getTasks()
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate())
expect(tasks[0].id).toEqual('id1')
expect(tasks[0].task).toEqual('test1')
})
it('should handle duration instead of a fixed date to determine end date without id', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','2013-01-01,4d');
var tasks = gDb.getTasks();
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime ).toEqual(moment('2013-01-05', 'YYYY-MM-DD').toDate());
expect(tasks[0].id ).toEqual('task1');
expect(tasks[0].task).toEqual('test1');
});
it('should handle relative start date based on id', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2w')
gDb.addTask('test2', 'id2,after id1,1d')
it('should handle relative start date of a fixed date to determine end date without id', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2w');
gDb.addTask('test2','after id1,1d');
var tasks = gDb.getTasks()
var tasks = gDb.getTasks();
expect(tasks[1].startTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate())
expect(tasks[1].id).toEqual('id2')
expect(tasks[1].task).toEqual('test2')
})
expect(tasks[1].startTime ).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate());
expect(tasks[1].id ).toEqual('task1');
expect(tasks[1].task).toEqual('test2');
});
it('should handle a new task with only an end date as definition', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2w');
gDb.addTask('test2','2013-01-26');
it('should handle relative start date based on id when id is invalid', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2w')
gDb.addTask('test2', 'id2,after id3,1d')
var tasks = gDb.getTasks()
expect(tasks[1].startTime).toEqual(new Date((new Date()).setHours(0, 0, 0, 0)))
expect(tasks[1].id).toEqual('id2')
expect(tasks[1].task).toEqual('test2')
})
var tasks = gDb.getTasks();
it('should handle fixed dates without id', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', '2013-01-01,2013-01-12')
var tasks = gDb.getTasks()
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2013-01-12', 'YYYY-MM-DD').toDate())
expect(tasks[0].id).toEqual('task1')
expect(tasks[0].task).toEqual('test1')
})
expect(tasks[1].startTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate());
expect(tasks[1].endTime ).toEqual(moment('2013-01-26', 'YYYY-MM-DD').toDate());
expect(tasks[1].id ).toEqual('task1');
expect(tasks[1].task).toEqual('test2');
});
it('should handle a new task with only an end date as definition', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2w');
gDb.addTask('test2','2d');
it('should handle duration instead of a fixed date to determine end date without id', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', '2013-01-01,4d')
var tasks = gDb.getTasks()
expect(tasks[0].startTime).toEqual(moment('2013-01-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2013-01-05', 'YYYY-MM-DD').toDate())
expect(tasks[0].id).toEqual('task1')
expect(tasks[0].task).toEqual('test1')
})
var tasks = gDb.getTasks();
it('should handle relative start date of a fixed date to determine end date without id', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2w')
gDb.addTask('test2', 'after id1,1d')
expect(tasks[1].startTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate());
expect(tasks[1].endTime ).toEqual(moment('2013-01-17', 'YYYY-MM-DD').toDate());
expect(tasks[1].id ).toEqual('task1');
expect(tasks[1].task).toEqual('test2');
});
it('should handle relative start date based on id regardless of sections', function () {
gDb.setDateFormat('YYYY-MM-DD');
gDb.addSection('testa1');
gDb.addTask('test1','id1,2013-01-01,2w');
gDb.addTask('test2','id2,after id3,1d');
gDb.addSection('testa2');
gDb.addTask('test3','id3,after id1,2d');
var tasks = gDb.getTasks()
var tasks = gDb.getTasks();
expect(tasks[1].startTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate())
expect(tasks[1].id).toEqual('task1')
expect(tasks[1].task).toEqual('test2')
})
it('should handle a new task with only an end date as definition', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2w')
gDb.addTask('test2', '2013-01-26')
expect(tasks[1].startTime ).toEqual(moment('2013-01-17', 'YYYY-MM-DD').toDate());
expect(tasks[1].endTime ).toEqual(moment('2013-01-18', 'YYYY-MM-DD').toDate());
expect(tasks[1].id ).toEqual('id2');
expect(tasks[1].task).toEqual('test2');
var tasks = gDb.getTasks()
expect(tasks[2].id ).toEqual('id3');
expect(tasks[2].task).toEqual('test3');
expect(tasks[2].startTime ).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate());
expect(tasks[2].endTime ).toEqual(moment('2013-01-17', 'YYYY-MM-DD').toDate());
});
expect(tasks[1].startTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate())
expect(tasks[1].endTime).toEqual(moment('2013-01-26', 'YYYY-MM-DD').toDate())
expect(tasks[1].id).toEqual('task1')
expect(tasks[1].task).toEqual('test2')
})
it('should handle a new task with only an end date as definition', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2w')
gDb.addTask('test2', '2d')
});
var tasks = gDb.getTasks()
expect(tasks[1].startTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate())
expect(tasks[1].endTime).toEqual(moment('2013-01-17', 'YYYY-MM-DD').toDate())
expect(tasks[1].id).toEqual('task1')
expect(tasks[1].task).toEqual('test2')
})
it('should handle relative start date based on id regardless of sections', function () {
gDb.setDateFormat('YYYY-MM-DD')
gDb.addSection('testa1')
gDb.addTask('test1', 'id1,2013-01-01,2w')
gDb.addTask('test2', 'id2,after id3,1d')
gDb.addSection('testa2')
gDb.addTask('test3', 'id3,after id1,2d')
var tasks = gDb.getTasks()
expect(tasks[1].startTime).toEqual(moment('2013-01-17', 'YYYY-MM-DD').toDate())
expect(tasks[1].endTime).toEqual(moment('2013-01-18', 'YYYY-MM-DD').toDate())
expect(tasks[1].id).toEqual('id2')
expect(tasks[1].task).toEqual('test2')
expect(tasks[2].id).toEqual('id3')
expect(tasks[2].task).toEqual('test3')
expect(tasks[2].startTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate())
expect(tasks[2].endTime).toEqual(moment('2013-01-17', 'YYYY-MM-DD').toDate())
})
})
// Ogiltigt id i after id

View File

@@ -1,339 +1,319 @@
var gantt = require('./parser/gantt').parser;
gantt.yy = require('./ganttDb');
var d3 = require('../../d3');
var moment = require('moment');
//var log = require('../../logger').create();
var gantt = require('./parser/gantt').parser
gantt.yy = require('./ganttDb')
var d3 = require('../../d3')
var moment = require('moment')
// var log = require('../../logger').create();
var daysInChart;
var daysInChart
var conf = {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
rightPadding: 75,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"'
};
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
rightPadding: 75,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"'
}
module.exports.setConf = function (cnf) {
var keys = Object.keys(cnf);
var keys = Object.keys(cnf)
keys.forEach(function (key) {
conf[key] = cnf[key];
});
};
var w;
keys.forEach(function (key) {
conf[key] = cnf[key]
})
}
var w
module.exports.draw = function (text, id) {
gantt.yy.clear();
gantt.parse(text);
gantt.yy.clear()
gantt.parse(text)
var elem = document.getElementById(id);
w = elem.parentElement.offsetWidth;
var elem = document.getElementById(id)
w = elem.parentElement.offsetWidth
if (typeof w === 'undefined') {
w = 1200;
}
if (typeof w === 'undefined') {
w = 1200
}
if(typeof conf.useWidth !== 'undefined'){
w = conf.useWidth;
}
if (typeof conf.useWidth !== 'undefined') {
w = conf.useWidth
}
var taskArray = gantt.yy.getTasks();
var taskArray = gantt.yy.getTasks()
// Set height based on number of tasks
var h = taskArray.length * (conf.barHeight + conf.barGap) + 2 * conf.topPadding;
var h = taskArray.length * (conf.barHeight + conf.barGap) + 2 * conf.topPadding
elem.setAttribute('height', '100%');
elem.setAttribute('height', '100%')
// Set viewBox
elem.setAttribute('viewBox','0 0 '+w+' '+h);
var svg = d3.select('#' + id);
elem.setAttribute('viewBox', '0 0 ' + w + ' ' + h)
var svg = d3.select('#' + id)
// var dateFormat = d3.time.format('%Y-%m-%d');
var startDate = d3.min(taskArray, function (d) {
return d.startTime
})
var endDate = d3.max(taskArray, function (d) {
return d.endTime
})
//var dateFormat = d3.time.format('%Y-%m-%d');
var startDate = d3.min(taskArray, function (d) {
return d.startTime;
});
var endDate = d3.max(taskArray, function (d) {
return d.endTime;
});
// Set timescale
var timeScale = d3.time.scale()
var timeScale = d3.time.scale()
.domain([d3.min(taskArray, function (d) {
return d.startTime;
return d.startTime
}),
d3.max(taskArray, function (d) {
return d.endTime;
})])
.rangeRound([0, w - conf.leftPadding - conf.rightPadding]);
//.nice(d3.time.monday);
d3.max(taskArray, function (d) {
return d.endTime
})])
.rangeRound([0, w - conf.leftPadding - conf.rightPadding])
// .nice(d3.time.monday);
var categories = [];
daysInChart = moment.duration(endDate-startDate).asDays();
var categories = []
for (var i = 0; i < taskArray.length; i++) {
categories.push(taskArray[i].type);
}
daysInChart = moment.duration(endDate - startDate).asDays()
var catsUnfiltered = categories; //for vert labels
for (var i = 0; i < taskArray.length; i++) {
categories.push(taskArray[i].type)
}
categories = checkUnique(categories);
var catsUnfiltered = categories // for vert labels
categories = checkUnique(categories)
makeGant(taskArray, w, h);
if(typeof conf.useWidth !== 'undefined'){
elem.setAttribute('width', w);
makeGant(taskArray, w, h)
if (typeof conf.useWidth !== 'undefined') {
elem.setAttribute('width', w)
}
}
svg.append('text')
svg.append('text')
.text(gantt.yy.getTitle())
.attr('x', w / 2)
.attr('y', conf.titleTopMargin)
.attr('class', 'titleText');
.attr('class', 'titleText')
function makeGant (tasks, pageWidth, pageHeight) {
var barHeight = conf.barHeight
var gap = barHeight + conf.barGap
var topPadding = conf.topPadding
var leftPadding = conf.leftPadding
function makeGant(tasks, pageWidth, pageHeight) {
var barHeight = conf.barHeight;
var gap = barHeight + conf.barGap;
var topPadding = conf.topPadding;
var leftPadding = conf.leftPadding;
var colorScale = d3.scale.linear()
var colorScale = d3.scale.linear()
.domain([0, categories.length])
.range(['#00B9FA', '#F95002'])
.interpolate(d3.interpolateHcl);
.interpolate(d3.interpolateHcl)
makeGrid(leftPadding, topPadding, pageWidth, pageHeight);
drawRects(tasks, gap, topPadding, leftPadding, barHeight, colorScale, pageWidth, pageHeight);
vertLabels(gap, topPadding, leftPadding, barHeight, colorScale);
drawToday(leftPadding, topPadding, pageWidth, pageHeight);
makeGrid(leftPadding, topPadding, pageWidth, pageHeight)
drawRects(tasks, gap, topPadding, leftPadding, barHeight, colorScale, pageWidth, pageHeight)
vertLabels(gap, topPadding, leftPadding, barHeight, colorScale)
drawToday(leftPadding, topPadding, pageWidth, pageHeight)
}
}
function drawRects(theArray, theGap, theTopPad, theSidePad, theBarHeight, theColorScale, w, h) { //eslint-disable-line no-unused-vars
svg.append('g')
function drawRects (theArray, theGap, theTopPad, theSidePad, theBarHeight, theColorScale, w, h) { // eslint-disable-line no-unused-vars
svg.append('g')
.selectAll('rect')
.data(theArray)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function (d, i) {
return i * theGap + theTopPad - 2;
return i * theGap + theTopPad - 2
})
.attr('width', function () {
return w - conf.rightPadding / 2;
return w - conf.rightPadding / 2
})
.attr('height', theGap)
.attr('class', function (d) { //eslint-disable-line no-unused-vars
for (var i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
return 'section section' + (i % conf.numberSectionStyles);
}
.attr('class', function (d) { // eslint-disable-line no-unused-vars
for (var i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
return 'section section' + (i % conf.numberSectionStyles)
}
return 'section section0';
});
}
return 'section section0'
})
var rectangles = svg.append('g')
var rectangles = svg.append('g')
.selectAll('rect')
.data(theArray)
.enter();
.enter()
rectangles.append('rect')
rectangles.append('rect')
.attr('rx', 3)
.attr('ry', 3)
.attr('x', function (d) {
return timeScale(d.startTime) + theSidePad;
return timeScale(d.startTime) + theSidePad
})
.attr('y', function (d, i) {
return i * theGap + theTopPad;
return i * theGap + theTopPad
})
.attr('width', function (d) {
return (timeScale(d.endTime) - timeScale(d.startTime));
return (timeScale(d.endTime) - timeScale(d.startTime))
})
.attr('height', theBarHeight)
.attr('class', function (d) {
var res = 'task ';
var secNum = 0;
for (var i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
secNum = (i % conf.numberSectionStyles);
}
}
if(d.active){
if (d.crit) {
return res + ' activeCrit'+secNum;
}else{
return res + ' active'+secNum;
}
}
var res = 'task '
if (d.done) {
if (d.crit) {
return res + ' doneCrit'+secNum;
}else{
return res + ' done'+secNum;
}
var secNum = 0
for (var i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
secNum = (i % conf.numberSectionStyles)
}
}
if (d.active) {
if (d.crit) {
return res + ' crit'+secNum;
return res + ' activeCrit' + secNum
} else {
return res + ' active' + secNum
}
}
if (d.done) {
if (d.crit) {
return res + ' doneCrit' + secNum
} else {
return res + ' done' + secNum
}
}
return res + ' task'+secNum;
if (d.crit) {
return res + ' crit' + secNum
}
return res + ' task' + secNum
})
;
rectangles.append('text')
rectangles.append('text')
.text(function (d) {
return d.task;
return d.task
})
.attr('font-size',conf.fontSize)
//.attr('font-family',conf.fontFamily)
.attr('font-size', conf.fontSize)
// .attr('font-family',conf.fontFamily)
.attr('x', function (d) {
var startX = timeScale(d.startTime),
endX = timeScale(d.endTime),
textWidth = this.getBBox().width;
var startX = timeScale(d.startTime),
endX = timeScale(d.endTime),
textWidth = this.getBBox().width
// Check id text width > width of rectangle
if (textWidth > (endX - startX)) {
if (endX + textWidth + 1.5*conf.leftPadding> w) {
return startX + theSidePad - 5;
} else {
return endX + theSidePad + 5;
}
if (textWidth > (endX - startX)) {
if (endX + textWidth + 1.5 * conf.leftPadding > w) {
return startX + theSidePad - 5
} else {
return (endX - startX) / 2 + startX + theSidePad;
return endX + theSidePad + 5
}
} else {
return (endX - startX) / 2 + startX + theSidePad
}
})
.attr('y', function (d, i) {
return i * theGap + (conf.barHeight / 2) + (conf.fontSize / 2 - 2) + theTopPad;
return i * theGap + (conf.barHeight / 2) + (conf.fontSize / 2 - 2) + theTopPad
})
//.attr('text-anchor', 'middle')
// .attr('text-anchor', 'middle')
.attr('text-height', theBarHeight)
.attr('class', function (d) {
var startX = timeScale(d.startTime),
endX = timeScale(d.endTime),
textWidth = this.getBBox().width;
var secNum = 0;
for (var i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
secNum = (i % conf.numberSectionStyles);
}
var startX = timeScale(d.startTime),
endX = timeScale(d.endTime),
textWidth = this.getBBox().width
var secNum = 0
for (var i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
secNum = (i % conf.numberSectionStyles)
}
}
var taskType = '';
if(d.active){
if (d.crit) {
taskType = 'activeCritText'+secNum;
}else{
taskType = 'activeText'+secNum;
}
var taskType = ''
if (d.active) {
if (d.crit) {
taskType = 'activeCritText' + secNum
} else {
taskType = 'activeText' + secNum
}
}
if (d.done) {
if (d.crit) {
taskType = taskType + ' doneCritText'+secNum;
}else{
taskType = taskType + ' doneText'+secNum;
}
}else{
if (d.crit) {
taskType = taskType + ' critText'+secNum;
}
if (d.done) {
if (d.crit) {
taskType = taskType + ' doneCritText' + secNum
} else {
taskType = taskType + ' doneText' + secNum
}
} else {
if (d.crit) {
taskType = taskType + ' critText' + secNum
}
}
// Check id text width > width of rectangle
if (textWidth > (endX - startX)) {
if (endX + textWidth + 1.5*conf.leftPadding > w) {
return 'taskTextOutsideLeft taskTextOutside' + secNum + ' ' + taskType;
} else {
return 'taskTextOutsideRight taskTextOutside' + secNum+ ' ' + taskType;
}
if (textWidth > (endX - startX)) {
if (endX + textWidth + 1.5 * conf.leftPadding > w) {
return 'taskTextOutsideLeft taskTextOutside' + secNum + ' ' + taskType
} else {
return 'taskText taskText' + secNum+ ' ' + taskType;
return 'taskTextOutsideRight taskTextOutside' + secNum + ' ' + taskType
}
});
} else {
return 'taskText taskText' + secNum + ' ' + taskType
}
})
}
}
function makeGrid(theSidePad, theTopPad, w, h) {
var pre = [
['.%L', function (d) {
return d.getMilliseconds();
}],
[':%S', function (d) {
return d.getSeconds();
}],
function makeGrid (theSidePad, theTopPad, w, h) {
var pre = [
['.%L', function (d) {
return d.getMilliseconds()
}],
[':%S', function (d) {
return d.getSeconds()
}],
// Within a hour
['h1 %I:%M', function (d) {
return d.getMinutes();
}]];
var post = [
['%Y', function () {
return true;
}]];
var mid = [
// Within a day
['%I:%M', function (d) {
return d.getHours();
}],
// Day within a week (not monday)
['%a %d', function (d) {
//return d.getDay() ==1;
return d.getDay() && d.getDate() != 1;
}],
// within a month
['%b %d', function (d) {
return d.getDate() != 1;
}],
// Month
['%B', function (d) {
return d.getMonth();
}]
];
var formatter;
if(typeof conf.axisFormatter !== 'undefined'){
mid = [];
conf.axisFormatter.forEach(function(item){
var n = [];
n[0] = item[0];
n[1] = item[1];
mid.push(n);
});
}
formatter = pre.concat(mid).concat(post);
['h1 %I:%M', function (d) {
return d.getMinutes()
}]]
var post = [
['%Y', function () {
return true
}]]
var xAxis = d3.svg.axis()
var mid = [
// Within a day
['%I:%M', function (d) {
return d.getHours()
}],
// Day within a week (not monday)
['%a %d', function (d) {
// return d.getDay() ==1;
return d.getDay() && d.getDate() != 1
}],
// within a month
['%b %d', function (d) {
return d.getDate() != 1
}],
// Month
['%B', function (d) {
return d.getMonth()
}]
]
var formatter
if (typeof conf.axisFormatter !== 'undefined') {
mid = []
conf.axisFormatter.forEach(function (item) {
var n = []
n[0] = item[0]
n[1] = item[1]
mid.push(n)
})
}
formatter = pre.concat(mid).concat(post)
var xAxis = d3.svg.axis()
.scale(timeScale)
.orient('bottom')
.tickSize(-h + theTopPad + conf.gridLineStartPadding, 0, 0)
.tickFormat(d3.time.format.multi(formatter))
;
if(daysInChart >7 && daysInChart<230){
xAxis = xAxis.ticks(d3.time.monday.range);
}
if (daysInChart > 7 && daysInChart < 230) {
xAxis = xAxis.ticks(d3.time.monday.range)
}
svg.append('g')
svg.append('g')
.attr('class', 'grid')
.attr('transform', 'translate(' + theSidePad + ', ' + (h - 50) + ')')
.call(xAxis)
@@ -342,87 +322,85 @@ module.exports.draw = function (text, id) {
.attr('fill', '#000')
.attr('stroke', 'none')
.attr('font-size', 10)
.attr('dy', '1em');
.attr('dy', '1em')
}
function vertLabels (theGap, theTopPad) {
var numOccurances = []
var prevGap = 0
for (var i = 0; i < categories.length; i++) {
numOccurances[i] = [categories[i], getCount(categories[i], catsUnfiltered)]
}
function vertLabels(theGap, theTopPad) {
var numOccurances = [];
var prevGap = 0;
for (var i = 0; i < categories.length; i++) {
numOccurances[i] = [categories[i], getCount(categories[i], catsUnfiltered)];
}
svg.append('g') //without doing this, impossible to put grid lines behind text
svg.append('g') // without doing this, impossible to put grid lines behind text
.selectAll('text')
.data(numOccurances)
.enter()
.append('text')
.text(function (d) {
return d[0];
return d[0]
})
.attr('x', 10)
.attr('y', function (d, i) {
if (i > 0) {
for (var j = 0; j < i; j++) {
prevGap += numOccurances[i - 1][1];
if (i > 0) {
for (var j = 0; j < i; j++) {
prevGap += numOccurances[i - 1][1]
// log.debug(prevGap);
return d[1] * theGap / 2 + prevGap * theGap + theTopPad;
}
} else {
return d[1] * theGap / 2 + theTopPad;
return d[1] * theGap / 2 + prevGap * theGap + theTopPad
}
} else {
return d[1] * theGap / 2 + theTopPad
}
})
.attr('class', function (d) {
for (var i = 0; i < categories.length; i++) {
if (d[0] === categories[i]) {
return 'sectionTitle sectionTitle' + (i % conf.numberSectionStyles);
}
for (var i = 0; i < categories.length; i++) {
if (d[0] === categories[i]) {
return 'sectionTitle sectionTitle' + (i % conf.numberSectionStyles)
}
return 'sectionTitle';
});
}
return 'sectionTitle'
})
}
}
function drawToday (theSidePad, theTopPad, w, h) {
var todayG = svg.append('g')
.attr('class', 'today')
function drawToday(theSidePad, theTopPad, w, h) {
var todayG = svg.append('g')
.attr('class', 'today');
var today = new Date()
var today = new Date();
todayG.append('line')
todayG.append('line')
.attr('x1', timeScale(today) + theSidePad)
.attr('x2', timeScale(today) + theSidePad)
.attr('y1', conf.titleTopMargin)
.attr('y2', h-conf.titleTopMargin)
.attr('y2', h - conf.titleTopMargin)
.attr('class', 'today')
;
}
}
//from this stackexchange question: http://stackoverflow.com/questions/1890203/unique-for-arrays-in-javascript
function checkUnique(arr) {
var hash = {}, result = [];
for (var i = 0, l = arr.length; i < l; ++i) {
if (!hash.hasOwnProperty(arr[i])) { //it works with objects! in FF, at least
hash[arr[i]] = true;
result.push(arr[i]);
}
}
return result;
// from this stackexchange question: http://stackoverflow.com/questions/1890203/unique-for-arrays-in-javascript
function checkUnique (arr) {
var hash = {}, result = []
for (var i = 0, l = arr.length; i < l; ++i) {
if (!hash.hasOwnProperty(arr[i])) { // it works with objects! in FF, at least
hash[arr[i]] = true
result.push(arr[i])
}
}
return result
}
//from this stackexchange question: http://stackoverflow.com/questions/14227981/count-how-many-strings-in-an-array-have-duplicates-in-the-same-array
function getCounts(arr) {
var i = arr.length, // var to loop over
obj = {}; // obj to store results
while (i) {
obj[arr[--i]] = (obj[arr[i]] || 0) + 1; // count occurrences
}
return obj;
// from this stackexchange question: http://stackoverflow.com/questions/14227981/count-how-many-strings-in-an-array-have-duplicates-in-the-same-array
function getCounts (arr) {
var i = arr.length, // var to loop over
obj = {} // obj to store results
while (i) {
obj[arr[--i]] = (obj[arr[i]] || 0) + 1 // count occurrences
}
return obj
}
// get specific from everything
function getCount(word, arr) {
return getCounts(arr)[word] || 0;
}
};
function getCount (word, arr) {
return getCounts(arr)[word] || 0
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,214 +1,211 @@
var Logger = require('../../logger');
var log = Logger.Log;
var _ = require('lodash');
var Logger = require('../../logger')
var log = Logger.Log
var _ = require('lodash')
var commits = {}
var head = null
var branches = { 'master': head }
var curBranch = 'master'
var direction = 'LR'
var seq = 0
var commits = {};
var head = null;
var branches = { 'master' : head };
var curBranch = 'master';
var direction = 'LR';
var seq = 0;
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
function getId() {
var pool='0123456789abcdef';
var id = '';
for (var i = 0; i < 7; i++) {
id += pool[getRandomInt(0,16)]
}
return id;
function getId () {
var pool = '0123456789abcdef'
var id = ''
for (var i = 0; i < 7; i++) {
id += pool[getRandomInt(0, 16)]
}
return id
}
function isfastforwardable(currentCommit, otherCommit) {
log.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id);
while (currentCommit.seq <= otherCommit.seq && currentCommit != otherCommit) {
function isfastforwardable (currentCommit, otherCommit) {
log.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id)
while (currentCommit.seq <= otherCommit.seq && currentCommit != otherCommit) {
// only if other branch has more commits
if (otherCommit.parent == null) break;
if (Array.isArray(otherCommit.parent)){
log.debug('In merge commit:', otherCommit.parent);
return isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) ||
if (otherCommit.parent == null) break
if (Array.isArray(otherCommit.parent)) {
log.debug('In merge commit:', otherCommit.parent)
return isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) ||
isfastforwardable(currentCommit, commits[otherCommit.parent[1]])
} else {
otherCommit = commits[otherCommit.parent];
}
}
log.debug(currentCommit.id, otherCommit.id);
return currentCommit.id == otherCommit.id;
}
function isReachableFrom(currentCommit, otherCommit) {
var currentSeq = currentCommit.seq;
var otherSeq = otherCommit.seq;
if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit);
return false;
}
exports.setDirection = function(dir) {
direction = dir;
}
var options = {};
exports.setOptions = function(rawOptString) {
log.debug('options str', rawOptString);
rawOptString = rawOptString && rawOptString.trim();
rawOptString = rawOptString || '{}';
try {
options = JSON.parse(rawOptString)
} catch(e) {
log.error('error while parsing gitGraph options', e.message);
}
}
exports.getOptions = function() {
return options;
}
exports.commit = function(msg) {
var commit = { id: getId(),
message: msg,
seq: seq++,
parent: head == null ? null : head.id};
head = commit;
commits[commit.id] = commit;
branches[curBranch] = commit.id;
log.debug('in pushCommit ' + commit.id);
}
exports.branch = function(name) {
branches[name] = head != null ? head.id: null;
log.debug('in createBranch');
}
exports.merge = function(otherBranch) {
var currentCommit = commits[branches[curBranch]];
var otherCommit = commits[branches[otherBranch]];
if (isReachableFrom(currentCommit, otherCommit)) {
log.debug('Already merged');
return;
}
if (isfastforwardable(currentCommit, otherCommit)){
branches[curBranch] = branches[otherBranch];
head = commits[branches[curBranch]];
} else {
otherCommit = commits[otherCommit.parent]
}
}
log.debug(currentCommit.id, otherCommit.id)
return currentCommit.id == otherCommit.id
}
function isReachableFrom (currentCommit, otherCommit) {
var currentSeq = currentCommit.seq
var otherSeq = otherCommit.seq
if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit)
return false
}
exports.setDirection = function (dir) {
direction = dir
}
var options = {}
exports.setOptions = function (rawOptString) {
log.debug('options str', rawOptString)
rawOptString = rawOptString && rawOptString.trim()
rawOptString = rawOptString || '{}'
try {
options = JSON.parse(rawOptString)
} catch (e) {
log.error('error while parsing gitGraph options', e.message)
}
}
exports.getOptions = function () {
return options
}
exports.commit = function (msg) {
var commit = { id: getId(),
message: msg,
seq: seq++,
parent: head == null ? null : head.id}
head = commit
commits[commit.id] = commit
branches[curBranch] = commit.id
log.debug('in pushCommit ' + commit.id)
}
exports.branch = function (name) {
branches[name] = head != null ? head.id : null
log.debug('in createBranch')
}
exports.merge = function (otherBranch) {
var currentCommit = commits[branches[curBranch]]
var otherCommit = commits[branches[otherBranch]]
if (isReachableFrom(currentCommit, otherCommit)) {
log.debug('Already merged')
return
}
if (isfastforwardable(currentCommit, otherCommit)) {
branches[curBranch] = branches[otherBranch]
head = commits[branches[curBranch]]
} else {
// create merge commit
var commit = {
id: getId(),
message: 'merged branch ' + otherBranch + ' into ' + curBranch,
seq: seq++,
parent: [head == null ? null : head.id, branches[otherBranch]]
};
head = commit;
commits[commit.id] = commit;
branches[curBranch] = commit.id;
var commit = {
id: getId(),
message: 'merged branch ' + otherBranch + ' into ' + curBranch,
seq: seq++,
parent: [head == null ? null : head.id, branches[otherBranch]]
}
log.debug(branches);
log.debug('in mergeBranch');
head = commit
commits[commit.id] = commit
branches[curBranch] = commit.id
}
log.debug(branches)
log.debug('in mergeBranch')
}
exports.checkout = function(branch) {
log.debug('in checkout');
curBranch = branch;
var id = branches[curBranch];
head = commits[id];
exports.checkout = function (branch) {
log.debug('in checkout')
curBranch = branch
var id = branches[curBranch]
head = commits[id]
}
exports.reset = function(commitRef) {
log.debug('in reset', commitRef);
var ref = commitRef.split(':')[0];
var parentCount = parseInt(commitRef.split(':')[1]);
var commit = ref == 'HEAD' ? head : commits[branches[ref]];
log.debug(commit, parentCount);
while (parentCount > 0) {
commit = commits[commit.parent];
parentCount--;
if (!commit) {
var err = 'Critical error - unique parent commit not found during reset';
log.error(err);
throw err;
}
exports.reset = function (commitRef) {
log.debug('in reset', commitRef)
var ref = commitRef.split(':')[0]
var parentCount = parseInt(commitRef.split(':')[1])
var commit = ref == 'HEAD' ? head : commits[branches[ref]]
log.debug(commit, parentCount)
while (parentCount > 0) {
commit = commits[commit.parent]
parentCount--
if (!commit) {
var err = 'Critical error - unique parent commit not found during reset'
log.error(err)
throw err
}
head = commit;
branches[curBranch] = commit.id;
}
head = commit
branches[curBranch] = commit.id
}
function upsert(arr, key, newval) {
var match = _.find(arr, key);
if(match){
var index = _.indexOf(arr, _.find(arr, key));
arr.splice(index, 1, newval);
function upsert (arr, key, newval) {
var match = _.find(arr, key)
if (match) {
var index = _.indexOf(arr, _.find(arr, key))
arr.splice(index, 1, newval)
} else {
arr.push(newval)
}
// console.log(arr);
}
function prettyPrintCommitHistory (commitArr) {
var commit = _.maxBy(commitArr, 'seq')
var line = ''
_.each(commitArr, function (c) {
if (c == commit) {
line += '\t*'
} else {
arr.push(newval);
line += '\t|'
}
//console.log(arr);
})
var label = [line, commit.id, commit.seq]
_.each(branches, function (v, k) {
if (v == commit.id) label.push(k)
})
log.debug(label.join(' '))
if (Array.isArray(commit.parent)) {
// console.log("here", commit.parent);
var newCommit = commits[commit.parent[0]]
upsert(commitArr, commit, newCommit)
commitArr.push(commits[commit.parent[1]])
// console.log("shoudl have 2", commitArr);
} else if (commit.parent == null) {
return
} else {
var nextCommit = commits[commit.parent]
upsert(commitArr, commit, nextCommit)
}
commitArr = _.uniqBy(commitArr, 'id')
prettyPrintCommitHistory(commitArr)
}
function prettyPrintCommitHistory(commitArr) {
var commit = _.maxBy(commitArr, 'seq');
var line = '';
_.each(commitArr, function(c) {
if (c == commit) {
line += '\t*'
} else {
line +='\t|'
}
});
var label = [line, commit.id, commit.seq];
_.each(branches, function(v,k){
if (v == commit.id) label.push(k);
});
log.debug(label.join(' '));
if (Array.isArray(commit.parent)) {
//console.log("here", commit.parent);
var newCommit = commits[commit.parent[0]];
upsert(commitArr, commit, newCommit);
commitArr.push(commits[commit.parent[1]]);
//console.log("shoudl have 2", commitArr);
} else if(commit.parent == null){
return;
} else {
var nextCommit = commits[commit.parent];
upsert(commitArr, commit, nextCommit);
}
commitArr = _.uniqBy(commitArr, 'id');
prettyPrintCommitHistory(commitArr);
}
exports.prettyPrint = function() {
log.debug(commits);
var node = exports.getCommitsArray()[0];
prettyPrintCommitHistory([node]);
exports.prettyPrint = function () {
log.debug(commits)
var node = exports.getCommitsArray()[0]
prettyPrintCommitHistory([node])
}
exports.clear = function () {
commits = {};
head = null;
branches = { 'master' : head };
curBranch = 'master';
seq =0;
commits = {}
head = null
branches = { 'master': head }
curBranch = 'master'
seq = 0
}
exports.getBranchesAsObjArray = function() {
var branchArr = _.map(branches, function(v,k) {
return {'name': k, 'commit': commits[v]};
});
//return _.orderBy(branchArr, [function(b) { return b.commit.seq}], ['desc']);
return branchArr;
exports.getBranchesAsObjArray = function () {
var branchArr = _.map(branches, function (v, k) {
return {'name': k, 'commit': commits[v]}
})
// return _.orderBy(branchArr, [function(b) { return b.commit.seq}], ['desc']);
return branchArr
}
exports.getBranches = function() { return branches; }
exports.getCommits = function() { return commits; }
exports.getCommitsArray = function() {
var commitArr = Object.keys(commits).map(function (key) {
return commits[key];
});
_.each(commitArr, function(o) { log.debug(o.id) });
return _.orderBy(commitArr, ['seq'], ['desc']);
}
exports.getCurrentBranch = function() { return curBranch; }
exports.getDirection = function() { return direction; }
exports.getHead = function() { return head; }
exports.getBranches = function () { return branches }
exports.getCommits = function () { return commits }
exports.getCommitsArray = function () {
var commitArr = Object.keys(commits).map(function (key) {
return commits[key]
})
_.each(commitArr, function (o) { log.debug(o.id) })
return _.orderBy(commitArr, ['seq'], ['desc'])
}
exports.getCurrentBranch = function () { return curBranch }
exports.getDirection = function () { return direction }
exports.getHead = function () { return head }

View File

@@ -1,211 +1,211 @@
var parser = require('./parser/gitGraph').parser;
var ast = require('./gitGraphAst.js');
describe('when parsing a gitGraph',function() {
'use strict';
beforeEach(function () {
console.log('ast',ast);
console.log('parser',parser);
parser.yy = ast;
parser.yy.clear();
});
it('should handle a gitGraph defintion', function () {
var str = 'gitGraph:\n' +
'commit\n';
var parser = require('./parser/gitGraph').parser
var ast = require('./gitGraphAst.js')
describe('when parsing a gitGraph', function () {
'use strict'
beforeEach(function () {
console.log('ast', ast)
console.log('parser', parser)
parser.yy = ast
parser.yy.clear()
})
it('should handle a gitGraph defintion', function () {
var str = 'gitGraph:\n' +
'commit\n'
parser.parse(str);
var commits = parser.yy.getCommits();
//console.log(commits);
parser.parse(str)
var commits = parser.yy.getCommits()
// console.log(commits);
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('master');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
});
expect(Object.keys(commits).length).toBe(1)
expect(parser.yy.getCurrentBranch()).toBe('master')
expect(parser.yy.getDirection()).toBe('LR')
expect(Object.keys(parser.yy.getBranches()).length).toBe(1)
})
it('should handle a gitGraph defintion with empty options', function () {
var str = 'gitGraph:\n' +
it('should handle a gitGraph defintion with empty options', function () {
var str = 'gitGraph:\n' +
'options\n' +
'end\n' +
'commit\n';
'commit\n'
parser.parse(str);
var commits = parser.yy.getCommits();
//console.log(commits);
parser.parse(str)
var commits = parser.yy.getCommits()
// console.log(commits);
expect(parser.yy.getOptions()).toEqual({});
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('master');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
});
expect(parser.yy.getOptions()).toEqual({})
expect(Object.keys(commits).length).toBe(1)
expect(parser.yy.getCurrentBranch()).toBe('master')
expect(parser.yy.getDirection()).toBe('LR')
expect(Object.keys(parser.yy.getBranches()).length).toBe(1)
})
it('should handle a gitGraph defintion with valid options', function () {
var str = 'gitGraph:\n' +
it('should handle a gitGraph defintion with valid options', function () {
var str = 'gitGraph:\n' +
'options\n' +
'{"key": "value"}\n' +
'end\n' +
'commit\n';
'commit\n'
parser.parse(str);
var commits = parser.yy.getCommits();
//console.log(commits);
//console.log('options object', parser.yy.getOptions());
expect(parser.yy.getOptions()['key']).toBe('value');
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('master');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
});
parser.parse(str)
var commits = parser.yy.getCommits()
// console.log(commits);
// console.log('options object', parser.yy.getOptions());
expect(parser.yy.getOptions()['key']).toBe('value')
expect(Object.keys(commits).length).toBe(1)
expect(parser.yy.getCurrentBranch()).toBe('master')
expect(parser.yy.getDirection()).toBe('LR')
expect(Object.keys(parser.yy.getBranches()).length).toBe(1)
})
it('should not fail on a gitGraph with malformed json', function () {
var str = 'gitGraph:\n' +
it('should not fail on a gitGraph with malformed json', function () {
var str = 'gitGraph:\n' +
'options\n' +
'{"key": "value"\n' +
'end\n' +
'commit\n';
'commit\n'
parser.parse(str);
var commits = parser.yy.getCommits();
//console.log(commits);
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('master');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
});
parser.parse(str)
var commits = parser.yy.getCommits()
// console.log(commits);
expect(Object.keys(commits).length).toBe(1)
expect(parser.yy.getCurrentBranch()).toBe('master')
expect(parser.yy.getDirection()).toBe('LR')
expect(Object.keys(parser.yy.getBranches()).length).toBe(1)
})
it('should handle set direction', function () {
var str = 'gitGraph BT:\n' +
'commit\n';
it('should handle set direction', function () {
var str = 'gitGraph BT:\n' +
'commit\n'
parser.parse(str);
var commits = parser.yy.getCommits();
//console.log(commits);
parser.parse(str)
var commits = parser.yy.getCommits()
// console.log(commits);
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('master');
expect(parser.yy.getDirection()).toBe('BT');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
});
expect(Object.keys(commits).length).toBe(1)
expect(parser.yy.getCurrentBranch()).toBe('master')
expect(parser.yy.getDirection()).toBe('BT')
expect(Object.keys(parser.yy.getBranches()).length).toBe(1)
})
it('should checkout a branch', function () {
var str = 'gitGraph:\n' +
it('should checkout a branch', function () {
var str = 'gitGraph:\n' +
'branch new\n' +
'checkout new\n'
parser.parse(str);
var commits = parser.yy.getCommits();
parser.parse(str)
var commits = parser.yy.getCommits()
expect(Object.keys(commits).length).toBe(0);
expect(parser.yy.getCurrentBranch()).toBe('new');
});
expect(Object.keys(commits).length).toBe(0)
expect(parser.yy.getCurrentBranch()).toBe('new')
})
it('should add commits to checked out branch', function () {
var str = 'gitGraph:\n' +
it('should add commits to checked out branch', function () {
var str = 'gitGraph:\n' +
'branch new\n' +
'checkout new\n' +
'commit\n'+
'commit\n' +
'commit\n'
parser.parse(str);
var commits = parser.yy.getCommits();
parser.parse(str)
var commits = parser.yy.getCommits()
expect(Object.keys(commits).length).toBe(2);
expect(parser.yy.getCurrentBranch()).toBe('new');
var branchCommit = parser.yy.getBranches()['new'];
expect(branchCommit).not.toBeNull();
expect(commits[branchCommit].parent).not.toBeNull();
});
it('should handle commit with args', function () {
var str = 'gitGraph:\n' +
'commit "a commit"\n';
expect(Object.keys(commits).length).toBe(2)
expect(parser.yy.getCurrentBranch()).toBe('new')
var branchCommit = parser.yy.getBranches()['new']
expect(branchCommit).not.toBeNull()
expect(commits[branchCommit].parent).not.toBeNull()
})
it('should handle commit with args', function () {
var str = 'gitGraph:\n' +
'commit "a commit"\n'
parser.parse(str);
var commits = parser.yy.getCommits();
//console.log(commits);
parser.parse(str)
var commits = parser.yy.getCommits()
// console.log(commits);
expect(Object.keys(commits).length).toBe(1);
var key = Object.keys(commits)[0];
expect(commits[key].message).toBe('a commit');
expect(parser.yy.getCurrentBranch()).toBe('master');
});
expect(Object.keys(commits).length).toBe(1)
var key = Object.keys(commits)[0]
expect(commits[key].message).toBe('a commit')
expect(parser.yy.getCurrentBranch()).toBe('master')
})
it('it should reset a branch', function () {
var str = 'gitGraph:\n' +
it('it should reset a branch', function () {
var str = 'gitGraph:\n' +
'commit\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'reset master\n';
'reset master\n'
parser.parse(str);
parser.parse(str)
var commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(3);
expect(parser.yy.getCurrentBranch()).toBe('newbranch');
expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']);
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']);
});
var commits = parser.yy.getCommits()
expect(Object.keys(commits).length).toBe(3)
expect(parser.yy.getCurrentBranch()).toBe('newbranch')
expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master'])
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch'])
})
it('reset can take an argument', function () {
var str = 'gitGraph:\n' +
it('reset can take an argument', function () {
var str = 'gitGraph:\n' +
'commit\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'reset master^\n';
'reset master^\n'
parser.parse(str);
parser.parse(str)
var commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(3);
expect(parser.yy.getCurrentBranch()).toBe('newbranch');
var master = commits[parser.yy.getBranches()['master']];
expect(parser.yy.getHead().id).toEqual(master.parent);
})
var commits = parser.yy.getCommits()
expect(Object.keys(commits).length).toBe(3)
expect(parser.yy.getCurrentBranch()).toBe('newbranch')
var master = commits[parser.yy.getBranches()['master']]
expect(parser.yy.getHead().id).toEqual(master.parent)
})
it('it should handle fast forwardable merges', function () {
var str = 'gitGraph:\n' +
it('it should handle fast forwardable merges', function () {
var str = 'gitGraph:\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'commit\n' +
'checkout master\n'+
'merge newbranch\n';
'checkout master\n' +
'merge newbranch\n'
parser.parse(str);
parser.parse(str)
var commits = parser.yy.getCommits();
//console.log(commits);
expect(Object.keys(commits).length).toBe(3);
expect(parser.yy.getCurrentBranch()).toBe('master');
expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']);
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']);
});
var commits = parser.yy.getCommits()
// console.log(commits);
expect(Object.keys(commits).length).toBe(3)
expect(parser.yy.getCurrentBranch()).toBe('master')
expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master'])
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch'])
})
it('it should handle cases when merge is a noop', function () {
var str = 'gitGraph:\n' +
it('it should handle cases when merge is a noop', function () {
var str = 'gitGraph:\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'commit\n' +
'merge master\n';
'merge master\n'
parser.parse(str);
parser.parse(str)
var commits = parser.yy.getCommits();
//console.log(commits);
expect(Object.keys(commits).length).toBe(3);
expect(parser.yy.getCurrentBranch()).toBe('newbranch');
expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']);
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']);
});
var commits = parser.yy.getCommits()
// console.log(commits);
expect(Object.keys(commits).length).toBe(3)
expect(parser.yy.getCurrentBranch()).toBe('newbranch')
expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master'])
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch'])
})
it('it should handle merge with 2 parents', function () {
var str = 'gitGraph:\n' +
it('it should handle merge with 2 parents', function () {
var str = 'gitGraph:\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
@@ -213,20 +213,20 @@ describe('when parsing a gitGraph',function() {
'commit\n' +
'checkout master\n' +
'commit\n' +
'merge newbranch\n';
'merge newbranch\n'
parser.parse(str);
parser.parse(str)
var commits = parser.yy.getCommits();
//console.log(commits);
expect(Object.keys(commits).length).toBe(5);
expect(parser.yy.getCurrentBranch()).toBe('master');
expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']);
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']);
});
var commits = parser.yy.getCommits()
// console.log(commits);
expect(Object.keys(commits).length).toBe(5)
expect(parser.yy.getCurrentBranch()).toBe('master')
expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master'])
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master'])
})
it('it should handle ff merge when history walk has two parents (merge commit)', function () {
var str = 'gitGraph:\n' +
it('it should handle ff merge when history walk has two parents (merge commit)', function () {
var str = 'gitGraph:\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
@@ -237,17 +237,17 @@ describe('when parsing a gitGraph',function() {
'merge newbranch\n' +
'commit\n' +
'checkout newbranch\n' +
'merge master\n' ;
'merge master\n'
parser.parse(str);
parser.parse(str)
var commits = parser.yy.getCommits();
//console.log(commits);
expect(Object.keys(commits).length).toBe(6);
expect(parser.yy.getCurrentBranch()).toBe('newbranch');
expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']);
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']);
var commits = parser.yy.getCommits()
// console.log(commits);
expect(Object.keys(commits).length).toBe(6)
expect(parser.yy.getCurrentBranch()).toBe('newbranch')
expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master'])
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master'])
parser.yy.prettyPrint();
});
});
parser.yy.prettyPrint()
})
})

View File

@@ -1,46 +1,45 @@
var db = require('./gitGraphAst');
var _ = require('lodash');
var gitGraphParser = require('./parser/gitGraph');
var d3 = require('../../d3');
var Logger = require('../../logger');
var log = Logger.Log;
var db = require('./gitGraphAst')
var _ = require('lodash')
var gitGraphParser = require('./parser/gitGraph')
var d3 = require('../../d3')
var Logger = require('../../logger')
var log = Logger.Log
var allCommitsDict = {};
var branchNum;
var allCommitsDict = {}
var branchNum
var config = {
nodeSpacing: 75,
nodeFillColor: 'yellow',
nodeStrokeWidth: 2,
nodeStrokeColor: 'grey',
lineStrokeWidth: 4,
branchOffset: 50,
lineColor: 'grey',
leftMargin: 50,
branchColors: ['#442f74', '#983351', '#609732', '#AA9A39'],
nodeRadius: 15,
nodeLabel: {
width: 75,
height: 100,
x: -25,
y: 15
}
nodeSpacing: 75,
nodeFillColor: 'yellow',
nodeStrokeWidth: 2,
nodeStrokeColor: 'grey',
lineStrokeWidth: 4,
branchOffset: 50,
lineColor: 'grey',
leftMargin: 50,
branchColors: ['#442f74', '#983351', '#609732', '#AA9A39'],
nodeRadius: 15,
nodeLabel: {
width: 75,
height: 100,
x: -25,
y: 15
}
}
var apiConfig = {};
exports.setConf = function(c) {
apiConfig = c;
var apiConfig = {}
exports.setConf = function (c) {
apiConfig = c
}
function svgCreateDefs(svg) {
svg
function svgCreateDefs (svg) {
svg
.append('defs')
.append('g')
.attr('id', 'def-commit')
.append('circle')
.attr('r', config.nodeRadius)
.attr('cx', 0)
.attr('cy', 0);
svg.select('#def-commit')
.attr('cy', 0)
svg.select('#def-commit')
.append('foreignObject')
.attr('width', config.nodeLabel.width)
.attr('height', config.nodeLabel.height)
@@ -49,234 +48,233 @@ function svgCreateDefs(svg) {
.attr('class', 'node-label')
.attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
.append('xhtml:p')
.html('');
.html('')
}
function svgDrawLine(svg, points, colorIdx, interpolate) {
interpolate = interpolate || 'basis';
var color = config.branchColors[colorIdx % config.branchColors.length];
var lineGen = d3.svg.line()
.x(function(d) {
return Math.round(d.x)
function svgDrawLine (svg, points, colorIdx, interpolate) {
interpolate = interpolate || 'basis'
var color = config.branchColors[colorIdx % config.branchColors.length]
var lineGen = d3.svg.line()
.x(function (d) {
return Math.round(d.x)
})
.y(function(d) {
return Math.round(d.y)
.y(function (d) {
return Math.round(d.y)
})
.interpolate(interpolate);
.interpolate(interpolate)
svg
svg
.append('svg:path')
.attr('d', lineGen(points))
.style('stroke', color)
.style('stroke-width', config.lineStrokeWidth)
.style('fill', 'none');
.style('fill', 'none')
}
// Pass in the element and its pre-transform coords
function getElementCoords(element, coords) {
coords = coords || element.node().getBBox();
var ctm = element.node().getCTM(),
xn = ctm.e + coords.x * ctm.a,
yn = ctm.f + coords.y * ctm.d;
//log.debug(ctm, coords);
return {
left: xn,
top: yn,
width: coords.width,
height: coords.height
};
function getElementCoords (element, coords) {
coords = coords || element.node().getBBox()
var ctm = element.node().getCTM(),
xn = ctm.e + coords.x * ctm.a,
yn = ctm.f + coords.y * ctm.d
// log.debug(ctm, coords);
return {
left: xn,
top: yn,
width: coords.width,
height: coords.height
}
}
function svgDrawLineForCommits(svg, fromId, toId, direction, color) {
log.debug('svgDrawLineForCommits: ', fromId, toId);
var fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle'));
var toBbox = getElementCoords(svg.select('#node-' + toId + ' circle'));
//log.debug('svgDrawLineForCommits: ', fromBbox, toBbox);
switch (direction) {
case 'LR':
function svgDrawLineForCommits (svg, fromId, toId, direction, color) {
log.debug('svgDrawLineForCommits: ', fromId, toId)
var fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle'))
var toBbox = getElementCoords(svg.select('#node-' + toId + ' circle'))
// log.debug('svgDrawLineForCommits: ', fromBbox, toBbox);
switch (direction) {
case 'LR':
// (toBbox)
// +--------
// + (fromBbox)
if (fromBbox.left - toBbox.left > config.nodeSpacing) {
var lineStart = { x: fromBbox.left - config.nodeSpacing, y: toBbox.top + toBbox.height/2};
var lineEnd ={ x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height/2 };
svgDrawLine(svg, [lineStart , lineEnd], color, 'linear')
svgDrawLine(svg, [
{x: fromBbox.left, y: fromBbox.top + fromBbox.height/2},
{x: fromBbox.left - config.nodeSpacing/2, y: fromBbox.top + fromBbox.height/2},
{x: fromBbox.left - config.nodeSpacing/2, y: lineStart.y},
lineStart], color);
} else {
svgDrawLine(svg, [{
'x': fromBbox.left,
'y': fromBbox.top + fromBbox.height / 2
}, {
'x': fromBbox.left - config.nodeSpacing/2,
'y': fromBbox.top + fromBbox.height / 2
}, {
'x': fromBbox.left - config.nodeSpacing/2,
'y': toBbox.top + toBbox.height / 2
}, {
'x': toBbox.left + toBbox.width,
'y': toBbox.top + toBbox.height / 2
}], color);
}
break;
case 'BT':
if (fromBbox.left - toBbox.left > config.nodeSpacing) {
var lineStart = { x: fromBbox.left - config.nodeSpacing, y: toBbox.top + toBbox.height / 2}
var lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 }
svgDrawLine(svg, [lineStart, lineEnd], color, 'linear')
svgDrawLine(svg, [
{x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2},
{x: fromBbox.left - config.nodeSpacing / 2, y: fromBbox.top + fromBbox.height / 2},
{x: fromBbox.left - config.nodeSpacing / 2, y: lineStart.y},
lineStart], color)
} else {
svgDrawLine(svg, [{
'x': fromBbox.left,
'y': fromBbox.top + fromBbox.height / 2
}, {
'x': fromBbox.left - config.nodeSpacing / 2,
'y': fromBbox.top + fromBbox.height / 2
}, {
'x': fromBbox.left - config.nodeSpacing / 2,
'y': toBbox.top + toBbox.height / 2
}, {
'x': toBbox.left + toBbox.width,
'y': toBbox.top + toBbox.height / 2
}], color)
}
break
case 'BT':
// + (fromBbox)
// |
// |
// + (toBbox)
if (toBbox.top - fromBbox.top > config.nodeSpacing) {
lineStart = { x: toBbox.left + toBbox.width/2, y: fromBbox.top + fromBbox.height + config.nodeSpacing};
lineEnd ={ x: toBbox.left + toBbox.width/2, y: toBbox.top };
svgDrawLine(svg, [lineStart , lineEnd], color, 'linear')
svgDrawLine(svg, [
{x: fromBbox.left + fromBbox.width/2, y: fromBbox.top + fromBbox.height},
{x: fromBbox.left + fromBbox.width/2, y: fromBbox.top + fromBbox.height + config.nodeSpacing/2},
{x: toBbox.left + toBbox.width/2, y: lineStart.y - config.nodeSpacing/2},
lineStart], color);
} else {
svgDrawLine(svg, [{
'x': fromBbox.left + fromBbox.width/2,
'y': fromBbox.top + fromBbox.height
}, {
'x': fromBbox.left + fromBbox.width/2,
'y': fromBbox.top + config.nodeSpacing/2
}, {
'x': toBbox.left + toBbox.width/2,
'y': toBbox.top - config.nodeSpacing/2
}, {
'x': toBbox.left + toBbox.width/2,
'y': toBbox.top
}], color);
}
break;
}
if (toBbox.top - fromBbox.top > config.nodeSpacing) {
lineStart = { x: toBbox.left + toBbox.width / 2, y: fromBbox.top + fromBbox.height + config.nodeSpacing}
lineEnd = { x: toBbox.left + toBbox.width / 2, y: toBbox.top }
svgDrawLine(svg, [lineStart, lineEnd], color, 'linear')
svgDrawLine(svg, [
{x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height},
{x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height + config.nodeSpacing / 2},
{x: toBbox.left + toBbox.width / 2, y: lineStart.y - config.nodeSpacing / 2},
lineStart], color)
} else {
svgDrawLine(svg, [{
'x': fromBbox.left + fromBbox.width / 2,
'y': fromBbox.top + fromBbox.height
}, {
'x': fromBbox.left + fromBbox.width / 2,
'y': fromBbox.top + config.nodeSpacing / 2
}, {
'x': toBbox.left + toBbox.width / 2,
'y': toBbox.top - config.nodeSpacing / 2
}, {
'x': toBbox.left + toBbox.width / 2,
'y': toBbox.top
}], color)
}
break
}
}
function cloneNode(svg, selector) {
return svg.select(selector).node().cloneNode(true);
function cloneNode (svg, selector) {
return svg.select(selector).node().cloneNode(true)
}
function renderCommitHistory(svg, commitid, branches, direction) {
var commit;
var numCommits = Object.keys(allCommitsDict).length;
if (_.isString(commitid)) {
do {
commit = allCommitsDict[commitid];
log.debug('in renderCommitHistory', commit.id, commit.seq);
if (svg.select('#node-' + commitid).size() > 0) {
return;
}
svg
.append(function() {
return cloneNode(svg, '#def-commit');
function renderCommitHistory (svg, commitid, branches, direction) {
var commit
var numCommits = Object.keys(allCommitsDict).length
if (_.isString(commitid)) {
do {
commit = allCommitsDict[commitid]
log.debug('in renderCommitHistory', commit.id, commit.seq)
if (svg.select('#node-' + commitid).size() > 0) {
return
}
svg
.append(function () {
return cloneNode(svg, '#def-commit')
})
.attr('class', 'commit')
.attr('id', function() {
return 'node-' + commit.id;
.attr('id', function () {
return 'node-' + commit.id
})
.attr('transform', function() {
switch (direction) {
case 'LR':
return 'translate(' + (commit.seq * config.nodeSpacing + config.leftMargin) + ', '
+ (branchNum * config.branchOffset) + ')';
case 'BT':
return 'translate(' + (branchNum * config.branchOffset + config.leftMargin) + ', '
+ ((numCommits - commit.seq) * config.nodeSpacing) + ')';
}
.attr('transform', function () {
switch (direction) {
case 'LR':
return 'translate(' + (commit.seq * config.nodeSpacing + config.leftMargin) + ', ' +
(branchNum * config.branchOffset) + ')'
case 'BT':
return 'translate(' + (branchNum * config.branchOffset + config.leftMargin) + ', ' +
((numCommits - commit.seq) * config.nodeSpacing) + ')'
}
})
.attr('fill', config.nodeFillColor)
.attr('stroke', config.nodeStrokeColor)
.attr('stroke-width', config.nodeStrokeWidth);
.attr('stroke-width', config.nodeStrokeWidth)
var branch = _.find(branches, ['commit', commit]);
if (branch) {
log.debug('found branch ', branch.name);
svg.select('#node-' + commit.id + ' p')
var branch = _.find(branches, ['commit', commit])
if (branch) {
log.debug('found branch ', branch.name)
svg.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'branch-label')
.text(branch.name + ', ');
}
svg.select('#node-' + commit.id + ' p')
.text(branch.name + ', ')
}
svg.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'commit-id')
.text(commit.id);
if (commit.message !== '' && direction === 'BT') {
svg.select('#node-' + commit.id + ' p')
.text(commit.id)
if (commit.message !== '' && direction === 'BT') {
svg.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'commit-msg')
.text( ', ' + commit.message);
}
commitid = commit.parent
} while (commitid && allCommitsDict[commitid]);
}
.text(', ' + commit.message)
}
commitid = commit.parent
} while (commitid && allCommitsDict[commitid])
}
if (_.isArray(commitid)) {
log.debug('found merge commmit', commitid);
renderCommitHistory(svg, commitid[0], branches, direction);
branchNum++;
renderCommitHistory(svg, commitid[1], branches, direction);
branchNum--;
}
if (_.isArray(commitid)) {
log.debug('found merge commmit', commitid)
renderCommitHistory(svg, commitid[0], branches, direction)
branchNum++
renderCommitHistory(svg, commitid[1], branches, direction)
branchNum--
}
}
function renderLines(svg, commit, direction, branchColor) {
branchColor = branchColor || 0;
while (commit.seq > 0 && !commit.lineDrawn) {
if (_.isString(commit.parent)) {
svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor);
commit.lineDrawn = true;
commit = allCommitsDict[commit.parent];
} else if (_.isArray(commit.parent)) {
svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor)
svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1)
renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1);
commit.lineDrawn = true;
commit = allCommitsDict[commit.parent[0]];
}
function renderLines (svg, commit, direction, branchColor) {
branchColor = branchColor || 0
while (commit.seq > 0 && !commit.lineDrawn) {
if (_.isString(commit.parent)) {
svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor)
commit.lineDrawn = true
commit = allCommitsDict[commit.parent]
} else if (_.isArray(commit.parent)) {
svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor)
svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1)
renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1)
commit.lineDrawn = true
commit = allCommitsDict[commit.parent[0]]
}
}
}
exports.draw = function(txt, id, ver) {
try {
var parser;
parser = gitGraphParser.parser;
parser.yy = db;
exports.draw = function (txt, id, ver) {
try {
var parser
parser = gitGraphParser.parser
parser.yy = db
log.debug('in gitgraph renderer', txt, id, ver);
log.debug('in gitgraph renderer', txt, id, ver)
// Parse the graph definition
parser.parse(txt + '\n');
parser.parse(txt + '\n')
config = _.extend(config, apiConfig, db.getOptions());
log.debug('effective options', config);
var direction = db.getDirection();
allCommitsDict = db.getCommits();
var branches = db.getBranchesAsObjArray();
if (direction === 'BT') {
config.nodeLabel.x = branches.length * config.branchOffset;
config.nodeLabel.width = '100%';
config.nodeLabel.y = -1 * 2* config.nodeRadius;
}
var svg = d3.select('#' + id);
svgCreateDefs(svg);
branchNum = 1;
_.each(branches, function(v) {
renderCommitHistory(svg, v.commit.id, branches, direction);
renderLines(svg, v.commit, direction);
branchNum++;
});
svg.attr('height', function() {
if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing;
return (branches.length + 1) * config.branchOffset;
});
//svg.attr('width', function() {
//if (direction === 'LR') return Object.keys(allCommitsDict).length * config.nodeSpacing + config.leftMargin;
//return (branches.length + 1) * config.branchOffset;
//});
} catch (e) {
log.error('Error while rendering gitgraph');
log.error(e.message);
config = _.extend(config, apiConfig, db.getOptions())
log.debug('effective options', config)
var direction = db.getDirection()
allCommitsDict = db.getCommits()
var branches = db.getBranchesAsObjArray()
if (direction === 'BT') {
config.nodeLabel.x = branches.length * config.branchOffset
config.nodeLabel.width = '100%'
config.nodeLabel.y = -1 * 2 * config.nodeRadius
}
};
var svg = d3.select('#' + id)
svgCreateDefs(svg)
branchNum = 1
_.each(branches, function (v) {
renderCommitHistory(svg, v.commit.id, branches, direction)
renderLines(svg, v.commit, direction)
branchNum++
})
svg.attr('height', function () {
if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing
return (branches.length + 1) * config.branchOffset
})
// svg.attr('width', function() {
// if (direction === 'LR') return Object.keys(allCommitsDict).length * config.nodeSpacing + config.leftMargin;
// return (branches.length + 1) * config.branchOffset;
// });
} catch (e) {
log.error('Error while rendering gitgraph')
log.error(e.message)
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,174 +1,171 @@
/**
* Created by knut on 14-11-19.
*/
var actors = {};
var messages = [];
var notes = [];
var title = '';
var Logger = require('../../logger');
var log = Logger.Log;
var actors = {}
var messages = []
var notes = []
var title = ''
var Logger = require('../../logger')
var log = Logger.Log
exports.addActor = function(id,name,description){
exports.addActor = function (id, name, description) {
// Don't allow description nulling
var old = actors[id];
if ( old && name === old.name && description == null ) return;
var old = actors[id]
if (old && name === old.name && description == null) return
// Don't allow null descriptions, either
if ( description == null ) description = name;
if (description == null) description = name
actors[id] = {name:name, description:description};
};
actors[id] = {name: name, description: description}
}
exports.addMessage = function(idFrom, idTo, message, answer){
messages.push({from:idFrom, to:idTo, message:message, answer:answer});
};
exports.addMessage = function (idFrom, idTo, message, answer) {
messages.push({from: idFrom, to: idTo, message: message, answer: answer})
}
/**
*
*/
exports.addSignal = function(idFrom, idTo, message, messageType){
log.debug('Adding message from='+idFrom+' to='+idTo+' message='+message+' type='+messageType);
messages.push({from:idFrom, to:idTo, message:message, type:messageType});
};
exports.getMessages = function(){
return messages;
};
exports.getActors = function(){
return actors;
};
exports.getActor = function(id){
return actors[id];
};
exports.getActorKeys = function(){
return Object.keys(actors);
};
exports.getTitle = function() {
return title;
exports.addSignal = function (idFrom, idTo, message, messageType) {
log.debug('Adding message from=' + idFrom + ' to=' + idTo + ' message=' + message + ' type=' + messageType)
messages.push({from: idFrom, to: idTo, message: message, type: messageType})
}
exports.clear = function(){
actors = {};
messages = [];
};
exports.getMessages = function () {
return messages
}
exports.getActors = function () {
return actors
}
exports.getActor = function (id) {
return actors[id]
}
exports.getActorKeys = function () {
return Object.keys(actors)
}
exports.getTitle = function () {
return title
}
exports.clear = function () {
actors = {}
messages = []
}
exports.LINETYPE = {
SOLID : 0 ,
DOTTED : 1 ,
NOTE : 2 ,
SOLID_CROSS : 3 ,
DOTTED_CROSS : 4 ,
SOLID_OPEN : 5 ,
DOTTED_OPEN : 6 ,
LOOP_START : 10 ,
LOOP_END : 11 ,
ALT_START : 12 ,
ALT_ELSE : 13 ,
ALT_END : 14 ,
OPT_START : 15 ,
OPT_END : 16 ,
ACTIVE_START : 17 ,
ACTIVE_END : 18 ,
PAR_START : 19 ,
PAR_AND : 20 ,
PAR_END : 21
};
exports.ARROWTYPE = {
FILLED : 0,
OPEN : 1
};
exports.PLACEMENT = {
LEFTOF : 0,
RIGHTOF : 1,
OVER : 2
};
exports.addNote = function (actor, placement, message){
var note = {actor:actor, placement: placement, message:message};
// Coerce actor into a [to, from, ...] array
var actors = [].concat(actor, actor);
notes.push(note);
messages.push({from:actors[0], to:actors[1], message:message, type:exports.LINETYPE.NOTE, placement: placement});
};
exports.setTitle = function(titleText){
title = titleText;
SOLID: 0,
DOTTED: 1,
NOTE: 2,
SOLID_CROSS: 3,
DOTTED_CROSS: 4,
SOLID_OPEN: 5,
DOTTED_OPEN: 6,
LOOP_START: 10,
LOOP_END: 11,
ALT_START: 12,
ALT_ELSE: 13,
ALT_END: 14,
OPT_START: 15,
OPT_END: 16,
ACTIVE_START: 17,
ACTIVE_END: 18,
PAR_START: 19,
PAR_AND: 20,
PAR_END: 21
}
exports.ARROWTYPE = {
FILLED: 0,
OPEN: 1
}
exports.parseError = function(err,hash){
global.mermaidAPI.parseError(err,hash);
};
exports.PLACEMENT = {
LEFTOF: 0,
RIGHTOF: 1,
OVER: 2
}
exports.apply = function(param){
if(param instanceof Array ){
param.forEach(function(item){
exports.apply(item);
});
} else {
exports.addNote = function (actor, placement, message) {
var note = {actor: actor, placement: placement, message: message}
// Coerce actor into a [to, from, ...] array
var actors = [].concat(actor, actor)
notes.push(note)
messages.push({from: actors[0], to: actors[1], message: message, type: exports.LINETYPE.NOTE, placement: placement})
}
exports.setTitle = function (titleText) {
title = titleText
}
exports.parseError = function (err, hash) {
global.mermaidAPI.parseError(err, hash)
}
exports.apply = function (param) {
if (param instanceof Array) {
param.forEach(function (item) {
exports.apply(item)
})
} else {
// console.info(param);
switch(param.type){
case 'addActor':
exports.addActor(param.actor, param.actor, param.description);
break;
case 'activeStart':
exports.addSignal(param.actor, undefined, undefined, param.signalType);
break;
case 'activeEnd':
exports.addSignal(param.actor, undefined, undefined, param.signalType);
break;
case 'addNote':
exports.addNote(param.actor,param.placement, param.text);
break;
case 'addMessage':
exports.addSignal(param.from, param.to, param.msg, param.signalType);
break;
case 'loopStart':
//log.debug('Loop text: ',param.loopText);
exports.addSignal(undefined, undefined, param.loopText, param.signalType);
//yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
break;
case 'loopEnd':
exports.addSignal(undefined, undefined, undefined, param.signalType);
break;
case 'optStart':
//log.debug('Loop text: ',param.loopText);
exports.addSignal(undefined, undefined, param.optText, param.signalType);
//yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
break;
case 'optEnd':
exports.addSignal(undefined, undefined, undefined, param.signalType);
break;
case 'altStart':
//log.debug('Loop text: ',param.loopText);
exports.addSignal(undefined, undefined, param.altText, param.signalType);
//yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
break;
case 'else':
exports.addSignal(undefined, undefined, param.altText, param.signalType);
break;
case 'altEnd':
exports.addSignal(undefined, undefined, undefined, param.signalType);
break;
case 'setTitle':
exports.setTitle(param.text);
break;
case 'parStart':
exports.addSignal(undefined, undefined, param.parText, param.signalType);
break;
case 'and':
exports.addSignal(undefined, undefined, param.parText, param.signalType);
break;
case 'parEnd':
exports.addSignal(undefined, undefined, undefined, param.signalType);
break;
}
switch (param.type) {
case 'addActor':
exports.addActor(param.actor, param.actor, param.description)
break
case 'activeStart':
exports.addSignal(param.actor, undefined, undefined, param.signalType)
break
case 'activeEnd':
exports.addSignal(param.actor, undefined, undefined, param.signalType)
break
case 'addNote':
exports.addNote(param.actor, param.placement, param.text)
break
case 'addMessage':
exports.addSignal(param.from, param.to, param.msg, param.signalType)
break
case 'loopStart':
// log.debug('Loop text: ',param.loopText);
exports.addSignal(undefined, undefined, param.loopText, param.signalType)
// yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
break
case 'loopEnd':
exports.addSignal(undefined, undefined, undefined, param.signalType)
break
case 'optStart':
// log.debug('Loop text: ',param.loopText);
exports.addSignal(undefined, undefined, param.optText, param.signalType)
// yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
break
case 'optEnd':
exports.addSignal(undefined, undefined, undefined, param.signalType)
break
case 'altStart':
// log.debug('Loop text: ',param.loopText);
exports.addSignal(undefined, undefined, param.altText, param.signalType)
// yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
break
case 'else':
exports.addSignal(undefined, undefined, param.altText, param.signalType)
break
case 'altEnd':
exports.addSignal(undefined, undefined, undefined, param.signalType)
break
case 'setTitle':
exports.setTitle(param.text)
break
case 'parStart':
exports.addSignal(undefined, undefined, param.parText, param.signalType)
break
case 'and':
exports.addSignal(undefined, undefined, param.parText, param.signalType)
break
case 'parEnd':
exports.addSignal(undefined, undefined, undefined, param.signalType)
break
}
};
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,157 +2,160 @@
* Created by knut on 14-11-23.
*/
var sq = require('./parser/sequenceDiagram').parser;
sq.yy = require('./sequenceDb');
var svgDraw = require('./svgDraw');
var d3 = require('../../d3');
var Logger = require('../../logger');
var log = Logger.Log;
var sq = require('./parser/sequenceDiagram').parser
sq.yy = require('./sequenceDb')
var svgDraw = require('./svgDraw')
var d3 = require('../../d3')
var Logger = require('../../logger')
var log = Logger.Log
var conf = {
diagramMarginX:50,
diagramMarginY:30,
diagramMarginX: 50,
diagramMarginY: 30,
// Margin between actors
actorMargin:50,
actorMargin: 50,
// Width of actor boxes
width:150,
width: 150,
// Height of actor boxes
height:65,
height: 65,
// Margin around loop boxes
boxMargin:10,
boxTextMargin:5,
noteMargin:10,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
// Space between messages
messageMargin:35,
//mirror actors under diagram
mirrorActors:false,
messageMargin: 35,
// mirror actors under diagram
mirrorActors: false,
// Depending on css styling this might need adjustment
// Prolongs the edge of the diagram downwards
bottomMarginAdj:1,
bottomMarginAdj: 1,
// width of activation box
activationWidth:10,
activationWidth: 10,
//text placement as: tspan | fo | old only text as before
textPlacement: 'tspan',
};
// text placement as: tspan | fo | old only text as before
textPlacement: 'tspan'
}
exports.bounds = {
data:{
startx:undefined,
stopx :undefined,
starty:undefined,
stopy :undefined
},
verticalPos:0,
data: {
startx: undefined,
stopx: undefined,
starty: undefined,
stopy: undefined
},
verticalPos: 0,
sequenceItems: [],
activations: [],
init : function(){
this.sequenceItems = [];
this.activations = [];
this.data = {
startx:undefined,
stopx :undefined,
starty:undefined,
stopy :undefined
};
this.verticalPos =0;
},
updateVal : function (obj,key,val,fun){
if(typeof obj[key] === 'undefined'){
obj[key] = val;
}else{
obj[key] = fun(val,obj[key]);
}
},
updateBounds:function(startx,starty,stopx,stopy){
var _self = this;
var cnt = 0;
function updateFn(type) { return function updateItemBounds(item) {
cnt++;
// The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems
var n = _self.sequenceItems.length-cnt+1;
_self.updateVal(item, 'starty',starty - n*conf.boxMargin, Math.min);
_self.updateVal(item, 'stopy' ,stopy + n*conf.boxMargin, Math.max);
_self.updateVal(exports.bounds.data, 'startx', startx - n * conf.boxMargin, Math.min);
_self.updateVal(exports.bounds.data, 'stopx', stopx + n * conf.boxMargin, Math.max);
if (!(type == 'activation')) {
_self.updateVal(item, 'startx',startx - n*conf.boxMargin, Math.min);
_self.updateVal(item, 'stopx' ,stopx + n*conf.boxMargin, Math.max);
_self.updateVal(exports.bounds.data, 'starty', starty - n * conf.boxMargin, Math.min);
_self.updateVal(exports.bounds.data, 'stopy', stopy + n * conf.boxMargin, Math.max);
}
}}
this.sequenceItems.forEach(updateFn());
this.activations.forEach(updateFn('activation'));
},
insert:function(startx,starty,stopx,stopy){
var _startx, _starty, _stopx, _stopy;
_startx = Math.min(startx,stopx);
_stopx = Math.max(startx,stopx);
_starty = Math.min(starty,stopy);
_stopy = Math.max(starty,stopy);
this.updateVal(exports.bounds.data,'startx',_startx,Math.min);
this.updateVal(exports.bounds.data,'starty',_starty,Math.min);
this.updateVal(exports.bounds.data,'stopx' ,_stopx ,Math.max);
this.updateVal(exports.bounds.data,'stopy' ,_stopy ,Math.max);
this.updateBounds(_startx,_starty,_stopx,_stopy);
},
newActivation:function(message, diagram){
var actorRect = sq.yy.getActors()[message.from.actor];
var stackedSize = actorActivations(message.from.actor).length;
var x = actorRect.x + conf.width/2 + (stackedSize-1)*conf.activationWidth/2;
this.activations.push({startx:x,starty:this.verticalPos+2,stopx:x+conf.activationWidth,stopy:undefined,
actor: message.from.actor,
anchored: svgDraw.anchorElement(diagram)
});
},
endActivation:function(message){
// find most recent activation for given actor
var lastActorActivationIdx = this.activations
.map(function(activation) { return activation.actor })
.lastIndexOf(message.from.actor);
var activation = this.activations.splice(lastActorActivationIdx, 1)[0];
return activation;
},
newLoop:function(title){
this.sequenceItems.push({startx:undefined,starty:this.verticalPos,stopx:undefined,stopy:undefined, title:title});
},
endLoop:function(){
var loop = this.sequenceItems.pop();
return loop;
},
addSectionToLoop: function(message) {
var loop = this.sequenceItems.pop();
loop.sections = loop.sections || [];
loop.sectionTitles = loop.sectionTitles || [];
loop.sections.push(exports.bounds.getVerticalPos());
loop.sectionTitles.push(message);
this.sequenceItems.push(loop);
},
bumpVerticalPos:function(bump){
this.verticalPos = this.verticalPos + bump;
this.data.stopy = this.verticalPos;
},
getVerticalPos:function(){
return this.verticalPos;
},
getBounds:function(){
return this.data;
sequenceItems: [],
activations: [],
init: function () {
this.sequenceItems = []
this.activations = []
this.data = {
startx: undefined,
stopx: undefined,
starty: undefined,
stopy: undefined
}
};
this.verticalPos = 0
},
updateVal: function (obj, key, val, fun) {
if (typeof obj[key] === 'undefined') {
obj[key] = val
} else {
obj[key] = fun(val, obj[key])
}
},
updateBounds: function (startx, starty, stopx, stopy) {
var _self = this
var cnt = 0
function updateFn (type) {
return function updateItemBounds (item) {
cnt++
// The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems
var n = _self.sequenceItems.length - cnt + 1
_self.updateVal(item, 'starty', starty - n * conf.boxMargin, Math.min)
_self.updateVal(item, 'stopy', stopy + n * conf.boxMargin, Math.max)
_self.updateVal(exports.bounds.data, 'startx', startx - n * conf.boxMargin, Math.min)
_self.updateVal(exports.bounds.data, 'stopx', stopx + n * conf.boxMargin, Math.max)
if (!(type == 'activation')) {
_self.updateVal(item, 'startx', startx - n * conf.boxMargin, Math.min)
_self.updateVal(item, 'stopx', stopx + n * conf.boxMargin, Math.max)
_self.updateVal(exports.bounds.data, 'starty', starty - n * conf.boxMargin, Math.min)
_self.updateVal(exports.bounds.data, 'stopy', stopy + n * conf.boxMargin, Math.max)
}
}
}
this.sequenceItems.forEach(updateFn())
this.activations.forEach(updateFn('activation'))
},
insert: function (startx, starty, stopx, stopy) {
var _startx, _starty, _stopx, _stopy
_startx = Math.min(startx, stopx)
_stopx = Math.max(startx, stopx)
_starty = Math.min(starty, stopy)
_stopy = Math.max(starty, stopy)
this.updateVal(exports.bounds.data, 'startx', _startx, Math.min)
this.updateVal(exports.bounds.data, 'starty', _starty, Math.min)
this.updateVal(exports.bounds.data, 'stopx', _stopx, Math.max)
this.updateVal(exports.bounds.data, 'stopy', _stopy, Math.max)
this.updateBounds(_startx, _starty, _stopx, _stopy)
},
newActivation: function (message, diagram) {
var actorRect = sq.yy.getActors()[message.from.actor]
var stackedSize = actorActivations(message.from.actor).length
var x = actorRect.x + conf.width / 2 + (stackedSize - 1) * conf.activationWidth / 2
this.activations.push({startx: x,
starty: this.verticalPos + 2,
stopx: x + conf.activationWidth,
stopy: undefined,
actor: message.from.actor,
anchored: svgDraw.anchorElement(diagram)
})
},
endActivation: function (message) {
// find most recent activation for given actor
var lastActorActivationIdx = this.activations
.map(function (activation) { return activation.actor })
.lastIndexOf(message.from.actor)
var activation = this.activations.splice(lastActorActivationIdx, 1)[0]
return activation
},
newLoop: function (title) {
this.sequenceItems.push({startx: undefined, starty: this.verticalPos, stopx: undefined, stopy: undefined, title: title})
},
endLoop: function () {
var loop = this.sequenceItems.pop()
return loop
},
addSectionToLoop: function (message) {
var loop = this.sequenceItems.pop()
loop.sections = loop.sections || []
loop.sectionTitles = loop.sectionTitles || []
loop.sections.push(exports.bounds.getVerticalPos())
loop.sectionTitles.push(message)
this.sequenceItems.push(loop)
},
bumpVerticalPos: function (bump) {
this.verticalPos = this.verticalPos + bump
this.data.stopy = this.verticalPos
},
getVerticalPos: function () {
return this.verticalPos
},
getBounds: function () {
return this.data
}
}
/**
* Draws an actor in the diagram with the attaced line
@@ -160,43 +163,42 @@ exports.bounds = {
* @param pos The position if the actor in the liost of actors
* @param description The text in the box
*/
var drawNote = function(elem, startx, verticalPos, msg, forceWidth){
var rect = svgDraw.getNoteRect();
rect.x = startx;
rect.y = verticalPos;
rect.width = forceWidth || conf.width;
rect.class = 'note';
var drawNote = function (elem, startx, verticalPos, msg, forceWidth) {
var rect = svgDraw.getNoteRect()
rect.x = startx
rect.y = verticalPos
rect.width = forceWidth || conf.width
rect.class = 'note'
var g = elem.append('g');
var rectElem = svgDraw.drawRect(g, rect);
var g = elem.append('g')
var rectElem = svgDraw.drawRect(g, rect)
var textObj = svgDraw.getTextObj();
textObj.x = startx-4;
textObj.y = verticalPos-13;
textObj.textMargin = conf.noteMargin;
textObj.dy = '1em';
textObj.text = msg.message;
textObj.class = 'noteText';
var textObj = svgDraw.getTextObj()
textObj.x = startx - 4
textObj.y = verticalPos - 13
textObj.textMargin = conf.noteMargin
textObj.dy = '1em'
textObj.text = msg.message
textObj.class = 'noteText'
var textElem = svgDraw.drawText(g,textObj, rect.width-conf.noteMargin);
var textElem = svgDraw.drawText(g, textObj, rect.width - conf.noteMargin)
var textHeight = textElem[0][0].getBBox().height;
if(!forceWidth && textHeight > conf.width){
textElem.remove();
g = elem.append('g');
var textHeight = textElem[0][0].getBBox().height
if (!forceWidth && textHeight > conf.width) {
textElem.remove()
g = elem.append('g')
textElem = svgDraw.drawText(g,textObj, 2*rect.width-conf.noteMargin);
textHeight = textElem[0][0].getBBox().height;
rectElem.attr('width',2*rect.width);
exports.bounds.insert(startx, verticalPos, startx + 2*rect.width, verticalPos + 2*conf.noteMargin + textHeight);
}else{
exports.bounds.insert(startx, verticalPos, startx + rect.width, verticalPos + 2*conf.noteMargin + textHeight);
}
rectElem.attr('height',textHeight+ 2*conf.noteMargin);
exports.bounds.bumpVerticalPos(textHeight+ 2*conf.noteMargin);
};
textElem = svgDraw.drawText(g, textObj, 2 * rect.width - conf.noteMargin)
textHeight = textElem[0][0].getBBox().height
rectElem.attr('width', 2 * rect.width)
exports.bounds.insert(startx, verticalPos, startx + 2 * rect.width, verticalPos + 2 * conf.noteMargin + textHeight)
} else {
exports.bounds.insert(startx, verticalPos, startx + rect.width, verticalPos + 2 * conf.noteMargin + textHeight)
}
rectElem.attr('height', textHeight + 2 * conf.noteMargin)
exports.bounds.bumpVerticalPos(textHeight + 2 * conf.noteMargin)
}
/**
* Draws a message
@@ -207,124 +209,118 @@ var drawNote = function(elem, startx, verticalPos, msg, forceWidth){
* @param txtCenter
* @param msg
*/
var drawMessage = function(elem, startx, stopx, verticalPos, msg){
var g = elem.append('g');
var txtCenter = startx + (stopx-startx)/2;
var drawMessage = function (elem, startx, stopx, verticalPos, msg) {
var g = elem.append('g')
var txtCenter = startx + (stopx - startx) / 2
var textElem = g.append('text') // text label for the x axis
var textElem = g.append('text') // text label for the x axis
.attr('x', txtCenter)
.attr('y', verticalPos - 7)
.style('text-anchor', 'middle')
.attr('class', 'messageText')
.text(msg.message);
.text(msg.message)
var textWidth;
var textWidth
if(typeof textElem[0][0].getBBox !== 'undefined'){
textWidth = textElem[0][0].getBBox().width;
}
else{
//textWidth = getBBox(textElem).width; //.getComputedTextLength()
textWidth = textElem[0][0].getBoundingClientRect();
//textWidth = textElem[0][0].getComputedTextLength();
}
if (typeof textElem[0][0].getBBox !== 'undefined') {
textWidth = textElem[0][0].getBBox().width
} else {
// textWidth = getBBox(textElem).width; //.getComputedTextLength()
textWidth = textElem[0][0].getBoundingClientRect()
// textWidth = textElem[0][0].getComputedTextLength();
}
var line;
var line
if(startx===stopx){
line = g.append('path')
.attr('d', 'M ' +startx+ ','+verticalPos+' C ' +(startx+60)+ ','+(verticalPos-10)+' ' +(startx+60)+ ',' +
(verticalPos+30)+' ' +startx+ ','+(verticalPos+20));
if (startx === stopx) {
line = g.append('path')
.attr('d', 'M ' + startx + ',' + verticalPos + ' C ' + (startx + 60) + ',' + (verticalPos - 10) + ' ' + (startx + 60) + ',' +
(verticalPos + 30) + ' ' + startx + ',' + (verticalPos + 20))
exports.bounds.bumpVerticalPos(30);
var dx = Math.max(textWidth/2,100);
exports.bounds.insert(startx-dx, exports.bounds.getVerticalPos() -10, stopx+dx, exports.bounds.getVerticalPos());
}else{
line = g.append('line');
line.attr('x1', startx);
line.attr('y1', verticalPos);
line.attr('x2', stopx);
line.attr('y2', verticalPos);
exports.bounds.insert(startx, exports.bounds.getVerticalPos() -10, stopx, exports.bounds.getVerticalPos());
}
//Make an SVG Container
//Draw the line
if (msg.type === sq.yy.LINETYPE.DOTTED || msg.type === sq.yy.LINETYPE.DOTTED_CROSS || msg.type === sq.yy.LINETYPE.DOTTED_OPEN) {
line.style('stroke-dasharray', ('3, 3'));
line.attr('class', 'messageLine1');
}
else {
line.attr('class', 'messageLine0');
}
exports.bounds.bumpVerticalPos(30)
var dx = Math.max(textWidth / 2, 100)
exports.bounds.insert(startx - dx, exports.bounds.getVerticalPos() - 10, stopx + dx, exports.bounds.getVerticalPos())
} else {
line = g.append('line')
line.attr('x1', startx)
line.attr('y1', verticalPos)
line.attr('x2', stopx)
line.attr('y2', verticalPos)
exports.bounds.insert(startx, exports.bounds.getVerticalPos() - 10, stopx, exports.bounds.getVerticalPos())
}
// Make an SVG Container
// Draw the line
if (msg.type === sq.yy.LINETYPE.DOTTED || msg.type === sq.yy.LINETYPE.DOTTED_CROSS || msg.type === sq.yy.LINETYPE.DOTTED_OPEN) {
line.style('stroke-dasharray', ('3, 3'))
line.attr('class', 'messageLine1')
} else {
line.attr('class', 'messageLine0')
}
var url = '';
if(conf.arrowMarkerAbsolute){
url = window.location.protocol+'//'+window.location.host+window.location.pathname +window.location.search;
url = url.replace(/\(/g,'\\(');
url = url.replace(/\)/g,'\\)');
}
var url = ''
if (conf.arrowMarkerAbsolute) {
url = window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search
url = url.replace(/\(/g, '\\(')
url = url.replace(/\)/g, '\\)')
}
line.attr('stroke-width', 2);
line.attr('stroke', 'black');
line.style('fill', 'none'); // remove any fill colour
if (msg.type === sq.yy.LINETYPE.SOLID || msg.type === sq.yy.LINETYPE.DOTTED){
line.attr('marker-end', 'url(' + url + '#arrowhead)');
}
line.attr('stroke-width', 2)
line.attr('stroke', 'black')
line.style('fill', 'none') // remove any fill colour
if (msg.type === sq.yy.LINETYPE.SOLID || msg.type === sq.yy.LINETYPE.DOTTED) {
line.attr('marker-end', 'url(' + url + '#arrowhead)')
}
if (msg.type === sq.yy.LINETYPE.SOLID_CROSS || msg.type === sq.yy.LINETYPE.DOTTED_CROSS){
line.attr('marker-end', 'url(' + url + '#crosshead)');
}
if (msg.type === sq.yy.LINETYPE.SOLID_CROSS || msg.type === sq.yy.LINETYPE.DOTTED_CROSS) {
line.attr('marker-end', 'url(' + url + '#crosshead)')
}
}
};
module.exports.drawActors = function(diagram, actors, actorKeys,verticalPos){
var i;
module.exports.drawActors = function (diagram, actors, actorKeys, verticalPos) {
var i
// Draw the actors
for(i=0;i<actorKeys.length;i++){
var key = actorKeys[i];
for (i = 0; i < actorKeys.length; i++) {
var key = actorKeys[i]
// Add some rendering data to the object
actors[key].x = i*conf.actorMargin +i*conf.width;
actors[key].y = verticalPos;
actors[key].width = conf.diagramMarginX;
actors[key].height = conf.diagramMarginY;
actors[key].x = i * conf.actorMargin + i * conf.width
actors[key].y = verticalPos
actors[key].width = conf.diagramMarginX
actors[key].height = conf.diagramMarginY
// Draw the box with the attached line
svgDraw.drawActor(diagram, actors[key].x, verticalPos, actors[key].description, conf);
exports.bounds.insert(actors[key].x, verticalPos, actors[key].x + conf.width, conf.height);
}
svgDraw.drawActor(diagram, actors[key].x, verticalPos, actors[key].description, conf)
exports.bounds.insert(actors[key].x, verticalPos, actors[key].x + conf.width, conf.height)
}
// Add a margin between the actor boxes and the first arrow
//exports.bounds.bumpVerticalPos(conf.height+conf.messageMargin);
exports.bounds.bumpVerticalPos(conf.height);
};
// exports.bounds.bumpVerticalPos(conf.height+conf.messageMargin);
exports.bounds.bumpVerticalPos(conf.height)
}
module.exports.setConf = function (cnf) {
var keys = Object.keys(cnf)
module.exports.setConf = function(cnf){
var keys = Object.keys(cnf);
keys.forEach(function (key) {
conf[key] = cnf[key]
})
}
keys.forEach(function(key){
conf[key] = cnf[key];
});
};
var actorActivations = function (actor) {
return module.exports.bounds.activations.filter(function (activation) {
return activation.actor == actor
})
}
var actorActivations = function(actor) {
return module.exports.bounds.activations.filter(function(activation) {
return activation.actor == actor;
});
};
var actorFlowVerticaBounds = function(actor) {
var actorFlowVerticaBounds = function (actor) {
// handle multiple stacked activations for same actor
var actors = sq.yy.getActors();
var activations = actorActivations(actor);
var actors = sq.yy.getActors()
var activations = actorActivations(actor)
var left = activations.reduce(function(acc,activation) { return Math.min(acc,activation.startx)}, actors[actor].x + conf.width/2);
var right = activations.reduce(function(acc,activation) { return Math.max(acc,activation.stopx)}, actors[actor].x + conf.width/2);
return [left,right];
};
var left = activations.reduce(function (acc, activation) { return Math.min(acc, activation.startx) }, actors[actor].x + conf.width / 2)
var right = activations.reduce(function (acc, activation) { return Math.max(acc, activation.stopx) }, actors[actor].x + conf.width / 2)
return [left, right]
}
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
@@ -332,184 +328,181 @@ var actorFlowVerticaBounds = function(actor) {
* @param id
*/
module.exports.draw = function (text, id) {
sq.yy.clear();
sq.parse(text+'\n');
sq.yy.clear()
sq.parse(text + '\n')
exports.bounds.init();
var diagram = d3.select('#'+id);
exports.bounds.init()
var diagram = d3.select('#' + id)
var startx;
var stopx;
var forceWidth;
var startx
var stopx
var forceWidth
// Fetch data from the parsing
var actors = sq.yy.getActors();
var actorKeys = sq.yy.getActorKeys();
var messages = sq.yy.getMessages();
var title = sq.yy.getTitle();
module.exports.drawActors(diagram, actors, actorKeys, 0);
var actors = sq.yy.getActors()
var actorKeys = sq.yy.getActorKeys()
var messages = sq.yy.getMessages()
var title = sq.yy.getTitle()
module.exports.drawActors(diagram, actors, actorKeys, 0)
// The arrow head definition is attached to the svg once
svgDraw.insertArrowHead(diagram);
svgDraw.insertArrowCrossHead(diagram);
svgDraw.insertArrowHead(diagram)
svgDraw.insertArrowCrossHead(diagram)
function activeEnd(msg, verticalPos) {
var activationData = exports.bounds.endActivation(msg);
if(activationData.starty + 18 > verticalPos) {
activationData.starty = verticalPos - 6;
verticalPos += 12;
}
svgDraw.drawActivation(diagram, activationData, verticalPos, conf);
exports.bounds.insert(activationData.startx, verticalPos -10, activationData.stopx, verticalPos);
function activeEnd (msg, verticalPos) {
var activationData = exports.bounds.endActivation(msg)
if (activationData.starty + 18 > verticalPos) {
activationData.starty = verticalPos - 6
verticalPos += 12
}
svgDraw.drawActivation(diagram, activationData, verticalPos, conf)
var lastMsg;
exports.bounds.insert(activationData.startx, verticalPos - 10, activationData.stopx, verticalPos)
}
var lastMsg
// Draw the messages/signals
messages.forEach(function(msg){
var loopData;
messages.forEach(function (msg) {
var loopData
switch(msg.type){
case sq.yy.LINETYPE.NOTE:
exports.bounds.bumpVerticalPos(conf.boxMargin);
switch (msg.type) {
case sq.yy.LINETYPE.NOTE:
exports.bounds.bumpVerticalPos(conf.boxMargin)
startx = actors[msg.from].x;
stopx = actors[msg.to].x;
startx = actors[msg.from].x
stopx = actors[msg.to].x
if(msg.placement === sq.yy.PLACEMENT.RIGHTOF){
drawNote(diagram, startx + (conf.width + conf.actorMargin)/2, exports.bounds.getVerticalPos(), msg);
}else if(msg.placement === sq.yy.PLACEMENT.LEFTOF){
drawNote(diagram, startx - (conf.width + conf.actorMargin)/2, exports.bounds.getVerticalPos(), msg);
}else if(msg.to === msg.from) {
if (msg.placement === sq.yy.PLACEMENT.RIGHTOF) {
drawNote(diagram, startx + (conf.width + conf.actorMargin) / 2, exports.bounds.getVerticalPos(), msg)
} else if (msg.placement === sq.yy.PLACEMENT.LEFTOF) {
drawNote(diagram, startx - (conf.width + conf.actorMargin) / 2, exports.bounds.getVerticalPos(), msg)
} else if (msg.to === msg.from) {
// Single-actor over
drawNote(diagram, startx, exports.bounds.getVerticalPos(), msg);
}else{
drawNote(diagram, startx, exports.bounds.getVerticalPos(), msg)
} else {
// Multi-actor over
forceWidth = Math.abs(startx - stopx) + conf.actorMargin;
drawNote(diagram, (startx + stopx + conf.width - forceWidth)/2, exports.bounds.getVerticalPos(), msg,
forceWidth);
}
break;
case sq.yy.LINETYPE.ACTIVE_START:
exports.bounds.newActivation(msg, diagram);
break;
case sq.yy.LINETYPE.ACTIVE_END:
activeEnd(msg, exports.bounds.getVerticalPos());
break;
case sq.yy.LINETYPE.LOOP_START:
exports.bounds.bumpVerticalPos(conf.boxMargin);
exports.bounds.newLoop(msg.message);
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case sq.yy.LINETYPE.LOOP_END:
loopData = exports.bounds.endLoop();
svgDraw.drawLoop(diagram, loopData,'loop', conf);
exports.bounds.bumpVerticalPos(conf.boxMargin);
break;
case sq.yy.LINETYPE.OPT_START:
exports.bounds.bumpVerticalPos(conf.boxMargin);
exports.bounds.newLoop(msg.message);
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case sq.yy.LINETYPE.OPT_END:
loopData = exports.bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'opt', conf);
exports.bounds.bumpVerticalPos(conf.boxMargin);
break;
case sq.yy.LINETYPE.ALT_START:
exports.bounds.bumpVerticalPos(conf.boxMargin);
exports.bounds.newLoop(msg.message);
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case sq.yy.LINETYPE.ALT_ELSE:
exports.bounds.bumpVerticalPos(conf.boxMargin);
loopData = exports.bounds.addSectionToLoop(msg.message);
exports.bounds.bumpVerticalPos(conf.boxMargin);
break;
case sq.yy.LINETYPE.ALT_END:
loopData = exports.bounds.endLoop();
svgDraw.drawLoop(diagram, loopData,'alt', conf);
exports.bounds.bumpVerticalPos(conf.boxMargin);
break;
case sq.yy.LINETYPE.PAR_START:
exports.bounds.bumpVerticalPos(conf.boxMargin);
exports.bounds.newLoop(msg.message);
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case sq.yy.LINETYPE.PAR_AND:
exports.bounds.bumpVerticalPos(conf.boxMargin);
loopData = exports.bounds.addSectionToLoop(msg.message);
exports.bounds.bumpVerticalPos(conf.boxMargin);
break;
case sq.yy.LINETYPE.PAR_END:
loopData = exports.bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'par', conf);
exports.bounds.bumpVerticalPos(conf.boxMargin);
break;
default:
try {
lastMsg = msg;
exports.bounds.bumpVerticalPos(conf.messageMargin);
var fromBounds = actorFlowVerticaBounds(msg.from);
var toBounds = actorFlowVerticaBounds(msg.to);
var fromIdx = fromBounds[0] <= toBounds[0]?1:0;
var toIdx = fromBounds[0] < toBounds[0]?0:1;
startx = fromBounds[fromIdx];
stopx = toBounds[toIdx];
var verticalPos = exports.bounds.getVerticalPos();
drawMessage(diagram, startx, stopx, verticalPos, msg);
var allBounds = fromBounds.concat(toBounds);
exports.bounds.insert(Math.min.apply(null, allBounds), verticalPos, Math.max.apply(null, allBounds), verticalPos);
} catch (e) {
console.error('error while drawing message', e);
}
forceWidth = Math.abs(startx - stopx) + conf.actorMargin
drawNote(diagram, (startx + stopx + conf.width - forceWidth) / 2, exports.bounds.getVerticalPos(), msg,
forceWidth)
}
});
break
case sq.yy.LINETYPE.ACTIVE_START:
exports.bounds.newActivation(msg, diagram)
break
case sq.yy.LINETYPE.ACTIVE_END:
activeEnd(msg, exports.bounds.getVerticalPos())
break
case sq.yy.LINETYPE.LOOP_START:
exports.bounds.bumpVerticalPos(conf.boxMargin)
exports.bounds.newLoop(msg.message)
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin)
break
case sq.yy.LINETYPE.LOOP_END:
loopData = exports.bounds.endLoop()
svgDraw.drawLoop(diagram, loopData, 'loop', conf)
exports.bounds.bumpVerticalPos(conf.boxMargin)
break
case sq.yy.LINETYPE.OPT_START:
exports.bounds.bumpVerticalPos(conf.boxMargin)
exports.bounds.newLoop(msg.message)
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin)
break
case sq.yy.LINETYPE.OPT_END:
loopData = exports.bounds.endLoop()
if(conf.mirrorActors){
// Draw actors below diagram
exports.bounds.bumpVerticalPos(conf.boxMargin*2);
module.exports.drawActors(diagram, actors, actorKeys, exports.bounds.getVerticalPos());
svgDraw.drawLoop(diagram, loopData, 'opt', conf)
exports.bounds.bumpVerticalPos(conf.boxMargin)
break
case sq.yy.LINETYPE.ALT_START:
exports.bounds.bumpVerticalPos(conf.boxMargin)
exports.bounds.newLoop(msg.message)
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin)
break
case sq.yy.LINETYPE.ALT_ELSE:
exports.bounds.bumpVerticalPos(conf.boxMargin)
loopData = exports.bounds.addSectionToLoop(msg.message)
exports.bounds.bumpVerticalPos(conf.boxMargin)
break
case sq.yy.LINETYPE.ALT_END:
loopData = exports.bounds.endLoop()
svgDraw.drawLoop(diagram, loopData, 'alt', conf)
exports.bounds.bumpVerticalPos(conf.boxMargin)
break
case sq.yy.LINETYPE.PAR_START:
exports.bounds.bumpVerticalPos(conf.boxMargin)
exports.bounds.newLoop(msg.message)
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin)
break
case sq.yy.LINETYPE.PAR_AND:
exports.bounds.bumpVerticalPos(conf.boxMargin)
loopData = exports.bounds.addSectionToLoop(msg.message)
exports.bounds.bumpVerticalPos(conf.boxMargin)
break
case sq.yy.LINETYPE.PAR_END:
loopData = exports.bounds.endLoop()
svgDraw.drawLoop(diagram, loopData, 'par', conf)
exports.bounds.bumpVerticalPos(conf.boxMargin)
break
default:
try {
lastMsg = msg
exports.bounds.bumpVerticalPos(conf.messageMargin)
var fromBounds = actorFlowVerticaBounds(msg.from)
var toBounds = actorFlowVerticaBounds(msg.to)
var fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0
var toIdx = fromBounds[0] < toBounds[0] ? 0 : 1
startx = fromBounds[fromIdx]
stopx = toBounds[toIdx]
var verticalPos = exports.bounds.getVerticalPos()
drawMessage(diagram, startx, stopx, verticalPos, msg)
var allBounds = fromBounds.concat(toBounds)
exports.bounds.insert(Math.min.apply(null, allBounds), verticalPos, Math.max.apply(null, allBounds), verticalPos)
} catch (e) {
console.error('error while drawing message', e)
}
}
})
var box = exports.bounds.getBounds();
if (conf.mirrorActors) {
// Draw actors below diagram
exports.bounds.bumpVerticalPos(conf.boxMargin * 2)
module.exports.drawActors(diagram, actors, actorKeys, exports.bounds.getVerticalPos())
}
var box = exports.bounds.getBounds()
// Adjust line height of actor lines now that the height of the diagram is known
log.debug('For line height fix Querying: #' + id + ' .actor-line');
var actorLines = d3.selectAll('#' + id + ' .actor-line');
actorLines.attr('y2',box.stopy);
log.debug('For line height fix Querying: #' + id + ' .actor-line')
var actorLines = d3.selectAll('#' + id + ' .actor-line')
actorLines.attr('y2', box.stopy)
var height = box.stopy - box.starty + 2 * conf.diagramMarginY
var height = box.stopy - box.starty + 2*conf.diagramMarginY;
if (conf.mirrorActors) {
height = height - conf.boxMargin + conf.bottomMarginAdj
}
if(conf.mirrorActors){
height = height - conf.boxMargin + conf.bottomMarginAdj;
}
var width = (box.stopx - box.startx) + (2 * conf.diagramMarginX)
var width = (box.stopx - box.startx) + (2 * conf.diagramMarginX);
if(title) {
diagram.append('text')
if (title) {
diagram.append('text')
.text(title)
.attr('x', ( ( box.stopx-box.startx) / 2 ) - ( 2 * conf.diagramMarginX ) )
.attr('y', -25);
}
.attr('x', ((box.stopx - box.startx) / 2) - (2 * conf.diagramMarginX))
.attr('y', -25)
}
if(conf.useMaxWidth) {
diagram.attr('height', '100%');
diagram.attr('width', '100%');
diagram.attr('style', 'max-width:' + (width) + 'px;');
}else{
diagram.attr('height',height);
diagram.attr('width', width );
}
var extraVertForTitle = title ? 40 : 0;
diagram.attr('viewBox', (box.startx - conf.diagramMarginX) + ' -' + (conf.diagramMarginY + extraVertForTitle) + ' ' + width + ' ' + (height + extraVertForTitle));
};
if (conf.useMaxWidth) {
diagram.attr('height', '100%')
diagram.attr('width', '100%')
diagram.attr('style', 'max-width:' + (width) + 'px;')
} else {
diagram.attr('height', height)
diagram.attr('width', width)
}
var extraVertForTitle = title ? 40 : 0
diagram.attr('viewBox', (box.startx - conf.diagramMarginX) + ' -' + (conf.diagramMarginY + extraVertForTitle) + ' ' + width + ' ' + (height + extraVertForTitle))
}

View File

@@ -1,140 +1,138 @@
/**
* Created by knut on 14-12-20.
*/
//var log = require('../../logger').create();
exports.drawRect = function(elem , rectData){
var rectElem = elem.append('rect');
rectElem.attr('x', rectData.x);
rectElem.attr('y', rectData.y);
rectElem.attr('fill', rectData.fill);
rectElem.attr('stroke', rectData.stroke);
rectElem.attr('width', rectData.width);
rectElem.attr('height', rectData.height);
rectElem.attr('rx', rectData.rx);
rectElem.attr('ry', rectData.ry);
// var log = require('../../logger').create();
exports.drawRect = function (elem, rectData) {
var rectElem = elem.append('rect')
rectElem.attr('x', rectData.x)
rectElem.attr('y', rectData.y)
rectElem.attr('fill', rectData.fill)
rectElem.attr('stroke', rectData.stroke)
rectElem.attr('width', rectData.width)
rectElem.attr('height', rectData.height)
rectElem.attr('rx', rectData.rx)
rectElem.attr('ry', rectData.ry)
if(typeof rectData.class !== 'undefined'){
rectElem.attr('class', rectData.class);
}
if (typeof rectData.class !== 'undefined') {
rectElem.attr('class', rectData.class)
}
return rectElem;
};
return rectElem
}
exports.drawText = function(elem, textData, width) {
exports.drawText = function (elem, textData, width) {
// Remove and ignore br:s
var nText = textData.text.replace(/<br\/?>/ig,' ');
var nText = textData.text.replace(/<br\/?>/ig, ' ')
var textElem = elem.append('text');
textElem.attr('x', textData.x);
textElem.attr('y', textData.y);
textElem.style('text-anchor', textData.anchor);
textElem.attr('fill', textData.fill);
if (typeof textData.class !== 'undefined') {
textElem.attr('class', textData.class);
}
var textElem = elem.append('text')
textElem.attr('x', textData.x)
textElem.attr('y', textData.y)
textElem.style('text-anchor', textData.anchor)
textElem.attr('fill', textData.fill)
if (typeof textData.class !== 'undefined') {
textElem.attr('class', textData.class)
}
/* textData.text.split(/<br\/?>/ig).forEach(function(rowText){
var span = textElem.append('tspan');
span.attr('x', textData.x +textData.textMargin);
span.attr('dy', textData.dy);
span.text(rowText);
});*/
}); */
var span = textElem.append('tspan')
// span.attr('x', textData.x);
span.attr('x', textData.x + textData.textMargin * 2)
// span.attr('dy', textData.dy);
span.attr('fill', textData.fill)
span.text(nText)
if (typeof textElem.textwrap !== 'undefined') {
textElem.textwrap({
x: textData.x, // bounding box is 300 pixels from the left
y: textData.y, // bounding box is 400 pixels from the top
width: width, // bounding box is 500 pixels across
height: 1800 // bounding box is 600 pixels tall
}, textData.textMargin)
}
var span = textElem.append('tspan');
//span.attr('x', textData.x);
span.attr('x', textData.x+textData.textMargin*2);
//span.attr('dy', textData.dy);
span.attr("fill", textData.fill);
span.text(nText);
if(typeof textElem.textwrap !== 'undefined'){
textElem.textwrap({
x: textData.x, // bounding box is 300 pixels from the left
y: textData.y, // bounding box is 400 pixels from the top
width: width, // bounding box is 500 pixels across
height: 1800 // bounding box is 600 pixels tall
}, textData.textMargin);
}
return textElem;
};
return textElem
}
exports.drawLabel = function (elem, txtObject) {
function genPoints(x, y, width, height, cut) {
return x + "," + y + " " +
(x + width) + "," + y + " " +
(x + width) + "," + (y + height - cut) + " " +
(x + width - cut * 1.2) + "," + (y + height) + " " +
(x) + "," + (y + height);
}
var polygon = elem.append("polygon");
polygon.attr("points" , genPoints(txtObject.x, txtObject.y, 50, 20, 7));
polygon.attr("style", "fill:#526e52;stroke:none");
function genPoints (x, y, width, height, cut) {
return x + ',' + y + ' ' +
(x + width) + ',' + y + ' ' +
(x + width) + ',' + (y + height - cut) + ' ' +
(x + width - cut * 1.2) + ',' + (y + height) + ' ' +
(x) + ',' + (y + height)
}
var polygon = elem.append('polygon')
polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7))
polygon.attr('style', 'fill:#526e52;stroke:none')
txtObject.y = txtObject.y + txtObject.labelMargin;
txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin;
txtObject.fill = 'white';
exports.drawText(elem, txtObject);
txtObject.y = txtObject.y + txtObject.labelMargin
txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin
txtObject.fill = 'white'
exports.drawText(elem, txtObject)
//return textElem;
};
var actorCnt = -1;
// return textElem;
}
var actorCnt = -1
/**
* Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor
* @param pos The position if the actor in the liost of actors
* @param description The text in the box
*/
exports.drawActor = function(elem, left, verticalPos, description,conf){
var center = left + (conf.width/2);
var g = elem.append('g');
if(verticalPos === 0) {
actorCnt++;
g.append('line')
.attr('id', 'actor'+actorCnt)
exports.drawActor = function (elem, left, verticalPos, description, conf) {
var center = left + (conf.width / 2)
var g = elem.append('g')
if (verticalPos === 0) {
actorCnt++
g.append('line')
.attr('id', 'actor' + actorCnt)
.attr('x1', center)
.attr('y1', 5)
.attr('x2', center)
.attr('y2', 2000)
.attr('class', 'actor-line')
.attr('stroke-width', '0.5px')
.attr('stroke', '#999');
}
.attr('stroke', '#999')
}
var rect = exports.getNoteRect();
rect.x = left;
rect.y = verticalPos;
rect.fill = '#eaeaea';
rect.width = conf.width;
rect.height = conf.height;
rect.class = 'actor';
rect.rx = 3;
rect.ry = 3;
exports.drawRect(g, rect);
var rect = exports.getNoteRect()
rect.x = left
rect.y = verticalPos
rect.fill = '#eaeaea'
rect.width = conf.width
rect.height = conf.height
rect.class = 'actor'
rect.rx = 3
rect.ry = 3
exports.drawRect(g, rect)
_drawTextCandidateFunc(conf)(description, g,
rect.x, rect.y, rect.width, rect.height, {'class':'actor'});
};
_drawTextCandidateFunc(conf)(description, g,
rect.x, rect.y, rect.width, rect.height, {'class': 'actor'})
}
exports.anchorElement = function(elem) {
return elem.append('g');
};
exports.anchorElement = function (elem) {
return elem.append('g')
}
/**
* Draws an actor in the diagram with the attaced line
* @param elem - element to append activation rect
* @param bounds - activation box bounds
* @param verticalPos - precise y cooridnate of bottom activation box edge
*/
exports.drawActivation = function(elem,bounds,verticalPos){
var rect = exports.getNoteRect();
var g = bounds.anchored;
rect.x = bounds.startx;
rect.y = bounds.starty;
rect.fill = '#f4f4f4';
rect.width = bounds.stopx - bounds.startx;
rect.height = verticalPos - bounds.starty;
exports.drawRect(g, rect);
};
exports.drawActivation = function (elem, bounds, verticalPos) {
var rect = exports.getNoteRect()
var g = bounds.anchored
rect.x = bounds.startx
rect.y = bounds.starty
rect.fill = '#f4f4f4'
rect.width = bounds.stopx - bounds.startx
rect.height = verticalPos - bounds.starty
exports.drawRect(g, rect)
}
/**
* Draws an actor in the diagram with the attaced line
@@ -142,63 +140,63 @@ exports.drawActivation = function(elem,bounds,verticalPos){
* @param pos The position if the actor in the list of actors
* @param description The text in the box
*/
exports.drawLoop = function(elem,bounds,labelText, conf){
var g = elem.append('g');
var drawLoopLine = function(startx,starty,stopx,stopy){
return g.append('line')
exports.drawLoop = function (elem, bounds, labelText, conf) {
var g = elem.append('g')
var drawLoopLine = function (startx, starty, stopx, stopy) {
return g.append('line')
.attr('x1', startx)
.attr('y1', starty)
.attr('x2', stopx )
.attr('y2', stopy )
.attr('x2', stopx)
.attr('y2', stopy)
.attr('stroke-width', 2)
.attr('stroke', '#526e52')
.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');
});
}
.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')
})
}
var txt = exports.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.class = 'labelText'; // Its size & position are fixed.
txt.fill = 'white';
var txt = exports.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.class = 'labelText' // Its size & position are fixed.
txt.fill = 'white'
exports.drawLabel(g,txt);
exports.drawLabel(g, txt)
txt = exports.getTextObj();
txt.text = '[ ' + bounds.title + ' ]';
txt.x = bounds.startx + (bounds.stopx - bounds.startx)/2;
txt.y = bounds.starty + 1.5 * conf.boxMargin;
txt.anchor = 'middle';
txt.class = 'loopText';
txt = exports.getTextObj()
txt.text = '[ ' + bounds.title + ' ]'
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2
txt.y = bounds.starty + 1.5 * conf.boxMargin
txt.anchor = 'middle'
txt.class = 'loopText'
exports.drawText(g,txt);
exports.drawText(g, txt)
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;
exports.drawText(g, txt);
}
});
}
};
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
exports.drawText(g, txt)
}
})
}
}
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
exports.insertArrowHead = function(elem){
elem.append('defs').append('marker')
exports.insertArrowHead = function (elem) {
elem.append('defs').append('marker')
.attr('id', 'arrowhead')
.attr('refX', 5)
.attr('refY', 2)
@@ -206,132 +204,131 @@ exports.insertArrowHead = function(elem){
.attr('markerHeight', 4)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 0,0 V 4 L6,2 Z'); //this is actual shape for arrowhead
};
.attr('d', 'M 0,0 V 4 L6,2 Z') // this is actual shape for arrowhead
}
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
exports.insertArrowCrossHead = function(elem){
var defs = elem.append('defs');
var marker = defs.append('marker')
exports.insertArrowCrossHead = function (elem) {
var defs = elem.append('defs')
var marker = defs.append('marker')
.attr('id', 'crosshead')
.attr('markerWidth', 15)
.attr('markerHeight', 8)
.attr('orient', 'auto')
.attr('refX', 16)
.attr('refY', 4);
.attr('refY', 4)
// The arrow
marker.append('path')
.attr('fill','black')
.attr('stroke','#000000')
marker.append('path')
.attr('fill', 'black')
.attr('stroke', '#000000')
.style('stroke-dasharray', ('0, 0'))
.attr('stroke-width','1px')
.attr('d', 'M 9,2 V 6 L16,4 Z');
.attr('stroke-width', '1px')
.attr('d', 'M 9,2 V 6 L16,4 Z')
// The cross
marker.append('path')
.attr('fill','none')
.attr('stroke','#000000')
marker.append('path')
.attr('fill', 'none')
.attr('stroke', '#000000')
.style('stroke-dasharray', ('0, 0'))
.attr('stroke-width','1px')
.attr('stroke-width', '1px')
.attr('d', 'M 0,1 L 6,7 M 6,1 L 0,7')
; //this is actual shape for arrowhead
// this is actual shape for arrowhead
}
};
exports.getTextObj = function () {
var txt = {
x: 0,
y: 0,
'fill': 'black',
'text-anchor': 'start',
style: '#666',
width: 100,
height: 100,
textMargin: 0,
rx: 0,
ry: 0
}
return txt
}
exports.getTextObj = function(){
var txt = {
x: 0,
y: 0,
'fill':'black',
'text-anchor': 'start',
style: '#666',
width: 100,
height: 100,
textMargin:0,
rx: 0,
ry: 0
};
return txt;
};
exports.getNoteRect = function () {
var rect = {
x: 0,
y: 0,
fill: '#EDF2AE',
stroke: '#666',
width: 100,
anchor: 'start',
height: 100,
rx: 0,
ry: 0
}
return rect
}
exports.getNoteRect = function(){
var rect = {
x : 0,
y : 0,
fill : '#EDF2AE',
stroke : '#666',
width : 100,
anchor : 'start',
height : 100,
rx : 0,
ry : 0
};
return rect;
};
var _drawTextCandidateFunc = (function() {
function byText(content, g, x, y, width, height, textAttrs) {
var text = g.append('text')
var _drawTextCandidateFunc = (function () {
function byText (content, g, x, y, width, height, textAttrs) {
var text = g.append('text')
.attr('x', x + width / 2).attr('y', y + height / 2 + 5)
.style('text-anchor', 'middle')
.text(content);
_setTextAttrs(text, textAttrs);
}
.text(content)
_setTextAttrs(text, textAttrs)
}
function byTspan(content, g, x, y, width, height, textAttrs) {
var text = g.append('text')
.attr('x', x + width / 2).attr('y', y)
.style('text-anchor', 'middle');
text.append('tspan')
.attr('x', x + width / 2).attr('dy', '0')
.text(content);
function byTspan (content, g, x, y, width, height, textAttrs) {
var text = g.append('text')
.attr('x', x + width / 2).attr('y', y)
.style('text-anchor', 'middle')
text.append('tspan')
.attr('x', x + width / 2).attr('dy', '0')
.text(content)
if(typeof(text.textwrap) !== 'undefined'){
text.textwrap({ //d3textwrap
x: x + width / 2, y: y, width: width, height: height
}, 0);
//vertical aligment after d3textwrap expans tspan to multiple tspans
var tspans = text.selectAll('tspan');
if (tspans.length > 0 && tspans[0].length > 0) {
tspans = tspans[0];
//set y of <text> to the mid y of the first line
text.attr('y', y + (height/2.0 - text[0][0].getBBox().height*(1 - 1.0/tspans.length)/2.0))
.attr("dominant-baseline", "central")
.attr("alignment-baseline", "central");
}
}
_setTextAttrs(text, textAttrs);
}
function byFo(content, g, x, y, width, height, textAttrs) {
var s = g.append('switch');
var f = s.append("foreignObject")
.attr('x', x).attr('y', y)
.attr('width', width).attr('height', height);
var text = f.append('div').style('display', 'table')
.style('height', '100%').style('width', '100%');
text.append('div').style('display', 'table-cell')
.style('text-align', 'center').style('vertical-align', 'middle')
.text(content);
byTspan(content, s, x, y, width, height, textAttrs);
_setTextAttrs(text, textAttrs);
}
function _setTextAttrs(toText, fromTextAttrsDict) {
for (var key in fromTextAttrsDict) {
if (fromTextAttrsDict.hasOwnProperty(key)) {
toText.attr(key, fromTextAttrsDict[key]);
}
if (typeof (text.textwrap) !== 'undefined') {
text.textwrap({ // d3textwrap
x: x + width / 2, y: y, width: width, height: height
}, 0)
// vertical aligment after d3textwrap expans tspan to multiple tspans
var tspans = text.selectAll('tspan')
if (tspans.length > 0 && tspans[0].length > 0) {
tspans = tspans[0]
// set y of <text> to the mid y of the first line
text.attr('y', y + (height / 2.0 - text[0][0].getBBox().height * (1 - 1.0 / tspans.length) / 2.0))
.attr('dominant-baseline', 'central')
.attr('alignment-baseline', 'central')
}
}
_setTextAttrs(text, textAttrs)
}
return function(conf) {
return conf.textPlacement==='fo' ? byFo : (
conf.textPlacement==='old' ? byText: byTspan);
};
})();
function byFo (content, g, x, y, width, height, textAttrs) {
var s = g.append('switch')
var f = s.append('foreignObject')
.attr('x', x).attr('y', y)
.attr('width', width).attr('height', height)
var text = f.append('div').style('display', 'table')
.style('height', '100%').style('width', '100%')
text.append('div').style('display', 'table-cell')
.style('text-align', 'center').style('vertical-align', 'middle')
.text(content)
byTspan(content, s, x, y, width, height, textAttrs)
_setTextAttrs(text, textAttrs)
}
function _setTextAttrs (toText, fromTextAttrsDict) {
for (var key in fromTextAttrsDict) {
if (fromTextAttrsDict.hasOwnProperty(key)) {
toText.attr(key, fromTextAttrsDict[key])
}
}
}
return function (conf) {
return conf.textPlacement === 'fo' ? byFo : (
conf.textPlacement === 'old' ? byText : byTspan)
}
})()