Skip to content

Commit

Permalink
Merge pull request #11 from mermaid-js/develop
Browse files Browse the repository at this point in the history
sync
  • Loading branch information
jgreywolf authored Jan 6, 2020
2 parents 00687f2 + 37ae863 commit ac8b01a
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 73 deletions.
4 changes: 3 additions & 1 deletion cypress/integration/rendering/classDiagram.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ describe('Class diagram', () => {
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Expand All @@ -29,7 +31,7 @@ describe('Class diagram', () => {
test()
}
`,
{}
{logLevel : 1}
);
cy.get('svg');
});
Expand Down
153 changes: 129 additions & 24 deletions docs/classDiagram.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,22 +169,26 @@ A relationship is a general term covering the specific types of logical connecti
There are different types of relations defined for classes under UML which are currently supported:

Type | Description
--- | ---
<\|--| Inheritance
*-- | Composition
o-- | Aggregation
--> | Association
-- | Link
--- | ---
<\|-- | Inheritance
*-- | Composition
o-- | Aggregation
--> | Association
-- | Link (Solid)
..> | Dependency
..\|> | Realization
.. | Link (Dashed)

<!--- TODO ..> Dependency--->
```
classDiagram
classA <|-- classB
classC *-- classD
classE o-- classF
classG <-- classH
classI <.. classJ
classK .. classL
classI -- classJ
classK <.. classL
classM <|.. classN
classO .. classP
```

Expand All @@ -194,30 +198,36 @@ classA <|-- classB
classC *-- classD
classE o-- classF
classG <-- classH
classI <.. classJ
classK .. classL
classI -- classJ
classK <.. classL
classM <|.. classN
classO .. classP
```
We can use the arrowheads in opposite directions as well :
We can use the labels to describe nature of relation between two classes. Also, arrowheads can be used in opposite directions as well :
```
classDiagram
classA --|> classB
classC --* classD
classE --o classF
classG <--> classH
classI ..> classJ
classK .. classL
classA --|> classB : Inheritance
classC --* classD : Composition
classE --o classF : Aggregation
classG --> classH : Association
classI -- classJ : Link(Solid)
classK ..> classL : Dependency
classM ..|> classN : Realization
classO .. classP : Link(Dashed)
```

```mermaid
classDiagram
classA --|> classB
classC --* classD
classE --o classF
classG <--> classH
classI ..> classJ
classK .. classL
classA --|> classB : Inheritance
classC --* classD : Composition
classE --o classF : Aggregation
classG --> classH : Association
classI -- classJ : Link(Solid)
classK ..> classL : Dependency
classM ..|> classN : Realization
classO .. classP : Link(Dashed)
```
Expand Down Expand Up @@ -345,6 +355,101 @@ class Shape{
```

## Interaction

It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab. **Note**: This functionality is disabled when using `securityLevel='strict'` and enabled when using `securityLevel='loose'`.

You would define these actions on a separate line after all classes have been declared.

```
action className "reference" "tooltip"
```

* _action_ is either `link` or `callback`, depending on which type of interaction you want to have called
* _className_ is the id of the node that the action will be associated with
* _reference_ is either the url link, or the function name for callback. (note: callback function will be called with the nodeId as parameter).
* (_optional_) tooltip is a string to be displayed when hovering over element (note: The styles of the tooltip are set by the class .mermaidTooltip.)

### Examples:

*URL Link:*

```
classDiagram
class Shape
link Shape "http://www.github.com" "This is a tooltip for a link"
```

*Callback:*

```
classDiagram
class Shape
callback Shape "callbackFunction" "This is a tooltip for a callback"
```

```
<script>
var callbackFunction = function(){
alert('A callback was triggered');
}
<script>
```

```mermaid
classDiagram
class Class01
class Class02
callback Class01 "callbackFunction" "Callback tooltip"
link Class02 "http://www.github.com" "This is a link"
```

> **Success** The tooltip functionality and the ability to link to urls are available from version 0.5.2.
Beginners tip, a full example using interactive links in an html context:
```
<body>
<div class="mermaid">
classDiagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
callback Duck callback "Tooltip"
click Zebra "http://www.github.com" "This is a link"
</div>
<script>
var callback = function(){
alert('A callback was triggered');
}
var config = {
startOnLoad:true,
securityLevel:'loose',
};
mermaid.initialize(config);
</script>
</body>
```

## Styling

Styling of the class diagram is done by defining a number of css classes. During rendering these classes are extracted from the file located at src/themes/class.scss
Expand Down
26 changes: 13 additions & 13 deletions src/diagrams/class/classDb.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as d3 from 'd3';
import { sanitizeUrl } from '@braintree/sanitize-url';
import { logger } from '../../logger';
import { getConfig } from '../../config';
import utils from '../../utils';

const MERMAID_DOM_ID_PREFIX = '';
const MERMAID_DOM_ID_PREFIX = 'classid-';

const config = getConfig();

Expand Down Expand Up @@ -155,14 +155,10 @@ export const setLink = function(ids, linkStr, tooltip) {
let id = _id;
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
if (typeof classes[id] !== 'undefined') {
if (config.securityLevel !== 'loose') {
classes[id].link = sanitizeUrl(linkStr);
} else {
classes[id].link = linkStr;
}
classes[id].link = utils.formatUrl(linkStr, config);

if (tooltip) {
classes[id].tooltip = tooltip;
classes[id].tooltip = utils.sanitize(tooltip, config);
}
}
});
Expand All @@ -182,24 +178,28 @@ export const setClickEvent = function(ids, functionName, tooltip) {
setCssClass(ids, 'clickable');
};

const setClickFunc = function(_id, functionName) {
const setClickFunc = function(_id, functionName, tooltip) {
let id = _id;
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
let elemId = MERMAID_DOM_ID_PREFIX + id;

if (config.securityLevel !== 'loose') {
return;
}
if (typeof functionName === 'undefined') {
return;
}
if (typeof classes[id] !== 'undefined') {
if (tooltip) {
classes[id].tooltip = utils.sanitize(tooltip, config);
}

funs.push(function() {
const elem = document.querySelector(`[id="${id}"]`);
const elem = document.querySelector(`[id="${elemId}"]`);
if (elem !== null) {
elem.setAttribute('title', classes[id].tooltip);
elem.addEventListener(
'click',
function() {
window[functionName](id);
window[functionName](elemId);
},
false
);
Expand Down
10 changes: 10 additions & 0 deletions src/diagrams/class/classDiagram.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@ describe('class diagram, ', function () {

parser.parse(str);
});
it('should handle dashed relation definition of different types and directions', function () {
const str =
'classDiagram\n' +
'Class11 <|.. Class12\n' +
'Class13 <.. Class14\n' +
'Class15 ..|> Class16\n' +
'Class17 ..> Class18\n' +
'Class19 .. Class20';
parser.parse(str);
});
});

describe('when fetching data from a classDiagram graph it', function () {
Expand Down
15 changes: 10 additions & 5 deletions src/diagrams/class/classRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { parser } from './parser/classDiagram';

parser.yy = classDb;

const MERMAID_DOM_ID_PREFIX = 'classid-';
let idCache = {};

let classCnt = 0;
const conf = {
dividerMargin: 10,
padding: 5,
Expand Down Expand Up @@ -183,6 +183,9 @@ const drawEdge = function(elem, path, relation) {
url = url.replace(/\)/g, '\\)');
}

if (relation.relation.lineType == 1) {
svgPath.attr('class', 'relation dashed-line');
}
if (relation.relation.type1 !== 'none') {
svgPath.attr(
'marker-start',
Expand Down Expand Up @@ -319,7 +322,7 @@ const drawClass = function(elem, classDef) {
}
};

const id = 'classId' + classCnt;
const id = MERMAID_DOM_ID_PREFIX + classDef.id;
const classInfo = {
id: id,
label: classDef.id,
Expand All @@ -339,8 +342,7 @@ const drawClass = function(elem, classDef) {
title = g
.append('svg:a')
.attr('xlink:href', classDef.link)
.attr('xlink:target', '_blank')
.attr('xlink:title', classDef.tooltip)
.attr('target', '_blank')
.append('text')
.attr('y', conf.textHeight + conf.padding)
.attr('x', 0);
Expand Down Expand Up @@ -432,14 +434,17 @@ const drawClass = function(elem, classDef) {
x.setAttribute('x', (rectWidth - x.getBBox().width) / 2);
});

if (classDef.tooltip) {
title.insert('title').text(classDef.tooltip);
}

membersLine.attr('x2', rectWidth);
methodsLine.attr('x2', rectWidth);

classInfo.width = rectWidth;
classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin;

idCache[id] = classInfo;
classCnt++;
return classInfo;
};

Expand Down
Loading

0 comments on commit ac8b01a

Please sign in to comment.