diff --git a/src/diagrams/class/classDb.js b/src/diagrams/class/classDb.js index d380639eb..cb4c42c8a 100644 --- a/src/diagrams/class/classDb.js +++ b/src/diagrams/class/classDb.js @@ -6,16 +6,18 @@ let classes = {}; /** * Function called by parser when a node definition has been found. * @param id + * @public */ export const addClass = function(id) { - if (typeof classes[id] === 'undefined') { - classes[id] = { - id: id, - methods: [], - members: [], - annotations: [] - }; - } + // Only add class if not exists + if (typeof classes[id] !== 'undefined') return; + + classes[id] = { + id: id, + methods: [], + members: [], + annotations: [] + }; }; export const clear = function() { @@ -41,15 +43,34 @@ export const addRelation = function(relation) { relations.push(relation); }; +/** + * Adds an annotation to the specified class + * Annotations mark special properties of the given type (like 'interface' or 'service') + * @param className The class name + * @param annotation The name of the annotation without any brackets + * @public + */ export const addAnnotation = function(className, annotation) { classes[className].annotations.push(annotation); }; +/** + * Adds a member to the specified class + * @param className The class name + * @param member The full name of the member. + * If the member is enclosed in <> it is treated as an annotation + * If the member is ending with a closing bracket ) it is treated as a method + * Otherwise the member will be treated as a normal property + * @public + */ export const addMember = function(className, member) { const theClass = classes[className]; if (typeof member === 'string') { + // Member can contain white spaces, we trim them out const memberString = member.trim(); + if (memberString.startsWith('<<') && memberString.endsWith('>>')) { + // Remove leading and trailing brackets theClass.annotations.push(memberString.substring(2, memberString.length - 2)); } else if (memberString.endsWith(')')) { theClass.methods.push(memberString); diff --git a/src/diagrams/class/classRenderer.js b/src/diagrams/class/classRenderer.js index 2ee1f0087..2d0825edc 100644 --- a/src/diagrams/class/classRenderer.js +++ b/src/diagrams/class/classRenderer.js @@ -255,10 +255,13 @@ const drawClass = function(elem, classDef) { height: 0 }; + // add class group const g = elem .append('g') .attr('id', id) .attr('class', 'classGroup'); + + // add title const title = g .append('text') .attr('y', conf.textHeight + conf.padding) @@ -278,6 +281,7 @@ const drawClass = function(elem, classDef) { .text(classDef.id) .attr('class', 'title'); + // If class has annotations the title needs to have an offset of the text height if (!isFirst) classTitle.attr('dy', conf.textHeight); const titleHeight = title.node().getBBox().height; @@ -324,21 +328,25 @@ const drawClass = function(elem, classDef) { }); const classBox = g.node().getBBox(); - g.insert('rect', ':first-child') + const rect = 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); + const rectWidth = rect.node().getBBox().width; + // Center title + // We subtract the width of each text element from the class box width and divide it by 2 title.node().childNodes.forEach(function(x) { - x.setAttribute('x', (classBox.width + 2 * conf.padding - x.getBBox().width) / 2); + x.setAttribute('x', (rectWidth - x.getBBox().width) / 2); }); - membersLine.attr('x2', classBox.width + 2 * conf.padding); - methodsLine.attr('x2', classBox.width + 2 * conf.padding); + membersLine.attr('x2', rectWidth); + methodsLine.attr('x2', rectWidth); - classInfo.width = classBox.width + 2 * conf.padding; + classInfo.width = rectWidth; classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin; idCache[id] = classInfo;