Add C4Context diagram. Compatible with C4-PlantUML syntax.

For an example, see the source code demos/index.html

 - System Context
 - Container diagram
 - Component diagram
 - Dynamic diagram
 - Deployment diagram
This commit is contained in:
pinghe 2022-05-17 19:57:03 +08:00
parent 9ba8e6e491
commit 28ca1420f9
6 changed files with 999 additions and 273 deletions

View File

@ -23,32 +23,33 @@
<div class="mermaid">
C4Context
title System Context diagram for Internet Banking System
Enterprise_Boundary(b0, "BankBoundary0") {
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")
Person(customerB, "Banking Customer B")
Person_Ext(customerC, "Banking Customer C")
System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")
Person_Ext(customerC, "Banking Customer C", "desc")
Person(customerD, "Banking Customer D", "A customer of the bank, <br/> with personal bank accounts.")
System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")
Enterprise_Boundary(b1, "BankBoundary") {
SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
System_Boundary(b2, "BankBoundary2") {
System(SystemA, "Banking System A")
System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts.")
System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts. next line.")
}
System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.")
Boundary(b3, "BankBoundary3", "boundary") {
SystemQueue(SystemF, "Banking System F Queue", "A system of the bank, with personal bank accounts.")
SystemQueue(SystemF, "Banking System F Queue", "A system of the bank.")
SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.")
}
}
}
BiRel(customerA, SystemAA, "Uses")
BiRel(SystemAA, SystemE, "Uses")
@ -56,6 +57,126 @@
Rel(SystemC, customerA, "Sends e-mails to")
</div>
<div class="mermaid">
C4Container
title Container diagram for Internet Banking System
System_Ext(email_system, "E-Mail System", "The internal Microsoft Exchange system")
Person(customer, Customer, "A customer of the bank, with personal bank accounts")
Container_Boundary(c1, "Internet Banking") {
Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to cutomers via their web browser")
Container_Ext(mobile_app, "Mobile App", "C#, Xamarin", "Provides a limited subset of the Internet banking functionality to customers via their mobile device")
Container(web_app, "Web Application", "Java, Spring MVC", "Delivers the static content and the Internet banking SPA")
ContainerDb(database, "Database", "SQL Database", "Stores user registration information, hashed auth credentials, access logs, etc.")
ContainerDb_Ext(backend_api, "API Application", "Java, Docker Container", "Provides Internet banking functionality via API")
}
System_Ext(banking_system, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
Rel(customer, web_app, "Uses", "HTTPS")
Rel(customer, spa, "Uses", "HTTPS")
Rel(customer, mobile_app, "Uses")
Rel(web_app, spa, "Delivers")
Rel(spa, backend_api, "Uses", "async, JSON/HTTPS")
Rel(mobile_app, backend_api, "Uses", "async, JSON/HTTPS")
Rel_Back(database, backend_api, "Reads from and writes to", "sync, JDBC")
Rel(email_system, customer, "Sends e-mails to")
Rel(backend_api, email_system, "Sends e-mails using", "sync, SMTP")
Rel(backend_api, banking_system, "Uses", "sync/async, XML/HTTPS")
</div>
<div class="mermaid">
C4Component
title Component diagram for Internet Banking System - API Application
Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.")
Container(ma, "Mobile App", "Xamarin", "Provides a limited subset ot the internet banking functionality to customers via their mobile mobile device.")
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
Container_Boundary(api, "API Application") {
Component(sign, "Sign In Controller", "MVC Rest Controlle", "Allows users to sign in to the internet banking system")
Component(accounts, "Accounts Summary Controller", "MVC Rest Controller", "Provides customers with a summary of their bank accounts")
Component(security, "Security Component", "Spring Bean", "Provides functionality related to singing in, changing passwords, etc.")
Component(mbsfacade, "Mainframe Banking System Facade", "Spring Bean", "A facade onto the mainframe banking system.")
Rel(sign, security, "Uses")
Rel(accounts, mbsfacade, "Uses")
Rel(security, db, "Read & write to", "JDBC")
Rel(mbsfacade, mbs, "Uses", "XML/HTTPS")
}
Rel_Back(spa, sign, "Uses", "JSON/HTTPS")
Rel(spa, accounts, "Uses", "JSON/HTTPS")
Rel(ma, sign, "Uses", "JSON/HTTPS")
Rel(ma, accounts, "Uses", "JSON/HTTPS")
</div>
<div class="mermaid">
C4Dynamic
title Dynamic diagram for Internet Banking System - API Application
ContainerDb(c4, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
Container(c1, "Single-Page Application", "JavaScript and Angular", "Provides all of the Internet banking functionality to customers via their web browser.")
Container_Boundary(b, "API Application") {
Component(c3, "Security Component", "Spring Bean", "Provides functionality Related to signing in, changing passwords, etc.")
Component(c2, "Sign In Controller", "Spring MVC Rest Controller", "Allows users to sign in to the Internet Banking System.")
}
Rel(c1, c2, "Submits credentials to", "JSON/HTTPS")
Rel(c2, c3, "Calls isAuthenticated() on")
Rel(c3, c4, "select * from users where username = ?", "JDBC")
</div>
<div class="mermaid">
C4Deployment
title Deployment Diagram for Internet Banking System - Live
Deployment_Node(mob, "Customer's mobile device", "Apple IOS or Android"){
Container(mobile, "Mobile App", "Xamarin", "Provides a limited subset of the Internet Banking functionality to customers via their mobile device.")
}
Deployment_Node(comp, "Customer's computer", "Mircosoft Windows or Apple macOS"){
Deployment_Node(browser, "Web Browser", "Google Chrome, Mozilla Firefox,<br/> Apple Safari or Microsoft Edge"){
Container(spa, "Single Page Application", "JavaScript and Angular", "Provides all of the Internet Banking functionality to customers via their web browser.")
}
}
Deployment_Node(plc, "Big Bank plc", "Big Bank plc data center"){
Deployment_Node(dn, "bigbank-api*** x8", "Ubuntu 16.04 LTS"){
Deployment_Node(apache, "Apache Tomcat", "Apache Tomcat 8.x"){
Container(api, "API Application", "Java and Spring MVC", "Provides Internet Banking functionality via a JSON/HTTPS API.")
}
}
Deployment_Node(bb2, "bigbank-web*** x4", "Ubuntu 16.04 LTS"){
Deployment_Node(apache2, "Apache Tomcat", "Apache Tomcat 8.x"){
Container(web, "Web Application", "Java and Spring MVC", "Delivers the static content and the Internet Banking single page application.")
}
}
Deployment_Node(bigbankdb01, "bigbank-db01", "Ubuntu 16.04 LTS"){
Deployment_Node(oracle, "Oracle - Primary", "Oracle 12c"){
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
}
}
Deployment_Node(bigbankdb02, "bigbank-db02", "Ubuntu 16.04 LTS") {
Deployment_Node(oracle2, "Oracle - Secondary", "Oracle 12c") {
ContainerDb(db2, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
}
}
}
Rel(mobile, api, "Makes API calls to", "json/HTTPS")
Rel(spa, api, "Makes API calls to", "json/HTTPS")
Rel_U(web, spa, "Delivers to the customer's web browser")
Rel(api, db, "Reads from and writes to", "JDBC")
Rel(api, db2, "Reads from and writes to", "JDBC")
Rel_R(db, db2, "Replicates data to")
</div>
<hr />
<div class="mermaid">

View File

@ -1098,7 +1098,7 @@ const config = {
* | --------- | --------------------- | ------- | -------- | ------------------ |
* | width | Width of person boxes | Integer | Required | Any Positive Value |
*
* **Notes:** Default value: 215
* **Notes:** Default value: 216
*/
width: 216,
@ -1107,7 +1107,7 @@ const config = {
* | --------- | ---------------------- | ------- | -------- | ------------------ |
* | height | Height of person boxes | Integer | Required | Any Positive Value |
*
* **Notes:** Default value: 65
* **Notes:** Default value: 60
*/
height: 60,
@ -1141,10 +1141,34 @@ const config = {
personFontFamily: '"Open Sans", sans-serif',
personFontWeight: 'normal',
external_personFontSize: 14,
external_personFontFamily: '"Open Sans", sans-serif',
external_personFontWeight: 'normal',
systemFontSize: 14,
systemFontFamily: '"Open Sans", sans-serif',
systemFontWeight: 'normal',
external_systemFontSize: 14,
external_systemFontFamily: '"Open Sans", sans-serif',
external_systemFontWeight: 'normal',
system_dbFontSize: 14,
system_dbFontFamily: '"Open Sans", sans-serif',
system_dbFontWeight: 'normal',
external_system_dbFontSize: 14,
external_system_dbFontFamily: '"Open Sans", sans-serif',
external_system_dbFontWeight: 'normal',
system_queueFontSize: 14,
system_queueFontFamily: '"Open Sans", sans-serif',
system_queueFontWeight: 'normal',
external_system_queueFontSize: 14,
external_system_queueFontFamily: '"Open Sans", sans-serif',
external_system_queueFontWeight: 'normal',
boundaryFontSize: 14,
boundaryFontFamily: '"Open Sans", sans-serif',
boundaryFontWeight: 'normal',
@ -1153,6 +1177,54 @@ const config = {
messageFontFamily: '"Open Sans", sans-serif',
messageFontWeight: 'normal',
containerFontSize: 14,
containerFontFamily: '"Open Sans", sans-serif',
containerFontWeight: 'normal',
external_containerFontSize: 14,
external_containerFontFamily: '"Open Sans", sans-serif',
external_containerFontWeight: 'normal',
container_dbFontSize: 14,
container_dbFontFamily: '"Open Sans", sans-serif',
container_dbFontWeight: 'normal',
external_container_dbFontSize: 14,
external_container_dbFontFamily: '"Open Sans", sans-serif',
external_container_dbFontWeight: 'normal',
container_queueFontSize: 14,
container_queueFontFamily: '"Open Sans", sans-serif',
container_queueFontWeight: 'normal',
external_container_queueFontSize: 14,
external_container_queueFontFamily: '"Open Sans", sans-serif',
external_container_queueFontWeight: 'normal',
componentFontSize: 14,
componentFontFamily: '"Open Sans", sans-serif',
componentFontWeight: 'normal',
external_componentFontSize: 14,
external_componentFontFamily: '"Open Sans", sans-serif',
external_componentFontWeight: 'normal',
component_dbFontSize: 14,
component_dbFontFamily: '"Open Sans", sans-serif',
component_dbFontWeight: 'normal',
external_component_dbFontSize: 14,
external_component_dbFontFamily: '"Open Sans", sans-serif',
external_component_dbFontWeight: 'normal',
component_queueFontSize: 14,
component_queueFontFamily: '"Open Sans", sans-serif',
component_queueFontWeight: 'normal',
external_component_queueFontSize: 14,
external_component_queueFontFamily: '"Open Sans", sans-serif',
external_component_queueFontWeight: 'normal',
/**
* This sets the auto-wrap state for the diagram
*
@ -1175,6 +1247,14 @@ const config = {
};
},
external_personFont: function () {
return {
fontFamily: this.external_personFontFamily,
fontSize: this.external_personFontSize,
fontWeight: this.external_personFontWeight,
};
},
systemFont: function () {
return {
fontFamily: this.systemFontFamily,
@ -1183,6 +1263,142 @@ const config = {
};
},
external_systemFont: function () {
return {
fontFamily: this.external_systemFontFamily,
fontSize: this.external_systemFontSize,
fontWeight: this.external_systemFontWeight,
};
},
system_dbFont: function () {
return {
fontFamily: this.system_dbFontFamily,
fontSize: this.system_dbFontSize,
fontWeight: this.system_dbFontWeight,
};
},
external_system_dbFont: function () {
return {
fontFamily: this.external_system_dbFontFamily,
fontSize: this.external_system_dbFontSize,
fontWeight: this.external_system_dbFontWeight,
};
},
system_queueFont: function () {
return {
fontFamily: this.system_queueFontFamily,
fontSize: this.system_queueFontSize,
fontWeight: this.system_queueFontWeight,
};
},
external_system_queueFont: function () {
return {
fontFamily: this.external_system_queueFontFamily,
fontSize: this.external_system_queueFontSize,
fontWeight: this.external_system_queueFontWeight,
};
},
containerFont: function () {
return {
fontFamily: this.containerFontFamily,
fontSize: this.containerFontSize,
fontWeight: this.containerFontWeight,
};
},
external_containerFont: function () {
return {
fontFamily: this.external_containerFontFamily,
fontSize: this.external_containerFontSize,
fontWeight: this.external_containerFontWeight,
};
},
container_dbFont: function () {
return {
fontFamily: this.container_dbFontFamily,
fontSize: this.container_dbFontSize,
fontWeight: this.container_dbFontWeight,
};
},
external_container_dbFont: function () {
return {
fontFamily: this.external_container_dbFontFamily,
fontSize: this.external_container_dbFontSize,
fontWeight: this.external_container_dbFontWeight,
};
},
container_queueFont: function () {
return {
fontFamily: this.container_queueFontFamily,
fontSize: this.container_queueFontSize,
fontWeight: this.container_queueFontWeight,
};
},
external_container_queueFont: function () {
return {
fontFamily: this.external_container_queueFontFamily,
fontSize: this.external_container_queueFontSize,
fontWeight: this.external_container_queueFontWeight,
};
},
componentFont: function () {
return {
fontFamily: this.componentFontFamily,
fontSize: this.componentFontSize,
fontWeight: this.componentFontWeight,
};
},
external_componentFont: function () {
return {
fontFamily: this.external_componentFontFamily,
fontSize: this.external_componentFontSize,
fontWeight: this.external_componentFontWeight,
};
},
component_dbFont: function () {
return {
fontFamily: this.component_dbFontFamily,
fontSize: this.component_dbFontSize,
fontWeight: this.component_dbFontWeight,
};
},
external_component_dbFont: function () {
return {
fontFamily: this.external_component_dbFontFamily,
fontSize: this.external_component_dbFontSize,
fontWeight: this.external_component_dbFontWeight,
};
},
component_queueFont: function () {
return {
fontFamily: this.component_queueFontFamily,
fontSize: this.component_queueFontSize,
fontWeight: this.component_queueFontWeight,
};
},
external_component_queueFont: function () {
return {
fontFamily: this.external_component_queueFontFamily,
fontSize: this.external_component_queueFontSize,
fontWeight: this.external_component_queueFontWeight,
};
},
boundaryFont: function () {
return {
fontFamily: this.boundaryFontFamily,
@ -1217,6 +1433,30 @@ const config = {
external_system_db_border_color: '#8A8A8A',
external_system_queue_bg_color: '#999999',
external_system_queue_border_color: '#8A8A8A',
container_bg_color: '#438DD5',
container_border_color: '#3C7FC0',
container_db_bg_color: '#438DD5',
container_db_border_color: '#3C7FC0',
container_queue_bg_color: '#438DD5',
container_queue_border_color: '#3C7FC0',
external_container_bg_color: '#B3B3B3',
external_container_border_color: '#A6A6A6',
external_container_db_bg_color: '#B3B3B3',
external_container_db_border_color: '#A6A6A6',
external_container_queue_bg_color: '#B3B3B3',
external_container_queue_border_color: '#A6A6A6',
component_bg_color: '#85BBF0',
component_border_color: '#78A8D8',
component_db_bg_color: '#85BBF0',
component_db_border_color: '#78A8D8',
component_queue_bg_color: '#85BBF0',
component_queue_border_color: '#78A8D8',
external_component_bg_color: '#CCCCCC',
external_component_border_color: '#BFBFBF',
external_component_db_bg_color: '#CCCCCC',
external_component_db_border_color: '#BFBFBF',
external_component_queue_bg_color: '#CCCCCC',
external_component_queue_border_color: '#BFBFBF',
},
};

View File

@ -3,7 +3,7 @@ import * as configApi from '../../config';
import { log } from '../../logger';
import { sanitizeText } from '../common/common';
let personOrSystemArray = [];
let c4ShapeArray = [];
let boundaryParseStack = [''];
let currentBoundaryParse = 'global';
let parentBoundaryParse = '';
@ -11,7 +11,7 @@ let boundarys = [
{
alias: 'global',
label: { text: 'global' },
type: 'global',
type: { text: 'global' },
tags: null,
link: null,
parentBoundary: '',
@ -21,14 +21,14 @@ let rels = [];
let title = '';
let wrapEnabled = false;
let description = '';
let c4Type = 'C4Context';
var c4Type;
export const getC4Type = function () {
return c4Type;
};
export const setC4Type = function (c4Type) {
let sanitizedText = sanitizeText(c4Type, configApi.getConfig());
export const setC4Type = function (c4TypeParam) {
let sanitizedText = sanitizeText(c4TypeParam, configApi.getConfig());
c4Type = sanitizedText;
};
@ -84,17 +84,17 @@ export const addRel = function (type, from, to, label, techn, descr, sprite, tag
};
//type, alias, label, ?descr, ?sprite, ?tags, $link
export const addPersonOrSystem = function (type, alias, label, descr, sprite, tags, link) {
export const addPersonOrSystem = function (typeC4Shape, alias, label, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
let personOrSystem = {};
const old = personOrSystemArray.find((personOrSystem) => personOrSystem.alias === alias);
const old = c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
if (old && alias === old.alias) {
personOrSystem = old;
} else {
personOrSystem.alias = alias;
personOrSystemArray.push(personOrSystem);
c4ShapeArray.push(personOrSystem);
}
// Don't allow null labels, either
@ -114,12 +114,94 @@ export const addPersonOrSystem = function (type, alias, label, descr, sprite, ta
personOrSystem.sprite = sprite;
personOrSystem.tags = tags;
personOrSystem.link = link;
personOrSystem.type = type;
personOrSystem.typeC4Shape = { text: typeC4Shape };
personOrSystem.parentBoundary = currentBoundaryParse;
};
//type, alias, label, ?techn, ?descr ?sprite, ?tags, $link
export const addContainer = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
let container = {};
const old = c4ShapeArray.find((container) => container.alias === alias);
if (old && alias === old.alias) {
container = old;
} else {
container.alias = alias;
c4ShapeArray.push(container);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
container.label = { text: '' };
} else {
container.label = { text: label };
}
if (techn === undefined || techn === null) {
container.techn = { text: '' };
} else {
container.techn = { text: techn };
}
if (descr === undefined || descr === null) {
container.descr = { text: '' };
} else {
container.descr = { text: descr };
}
container.sprite = sprite;
container.tags = tags;
container.link = link;
container.wrap = autoWrap();
container.typeC4Shape = { text: typeC4Shape };
container.parentBoundary = currentBoundaryParse;
};
//type, alias, label, ?techn, ?descr ?sprite, ?tags, $link
export const addComponent = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
let component = {};
const old = c4ShapeArray.find((component) => component.alias === alias);
if (old && alias === old.alias) {
component = old;
} else {
component.alias = alias;
c4ShapeArray.push(component);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
component.label = { text: '' };
} else {
component.label = { text: label };
}
if (techn === undefined || techn === null) {
component.techn = { text: '' };
} else {
component.techn = { text: techn };
}
if (descr === undefined || descr === null) {
component.descr = { text: '' };
} else {
component.descr = { text: descr };
}
component.sprite = sprite;
component.tags = tags;
component.link = link;
component.wrap = autoWrap();
component.typeC4Shape = { text: typeC4Shape };
component.parentBoundary = currentBoundaryParse;
};
//alias, label, ?type, ?tags, $link
export const addBoundary = function (alias, label, type, tags, link) {
export const addPersonOrSystemBoundary = function (alias, label, type, tags, link) {
// if (parentBoundary === null) return;
// Don't allow label nulling
@ -147,11 +229,104 @@ export const addBoundary = function (alias, label, type, tags, link) {
boundary.type = { text: type };
}
boundary.wrap = autoWrap();
boundary.tags = tags;
boundary.link = link;
boundary.type = type;
boundary.parentBoundary = currentBoundaryParse;
boundary.wrap = autoWrap();
parentBoundaryParse = currentBoundaryParse;
currentBoundaryParse = alias;
boundaryParseStack.push(parentBoundaryParse);
};
//alias, label, ?type, ?tags, $link
export const addContainerBoundary = function (alias, label, type, tags, link) {
// if (parentBoundary === null) return;
// Don't allow label nulling
if (alias === null || label === null) return;
let boundary = {};
const old = boundarys.find((boundary) => boundary.alias === alias);
if (old && alias === old.alias) {
boundary = old;
} else {
boundary.alias = alias;
boundarys.push(boundary);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
boundary.label = { text: '' };
} else {
boundary.label = { text: label };
}
if (type === undefined || type === null) {
boundary.type = { text: 'container' };
} else {
boundary.type = { text: type };
}
boundary.tags = tags;
boundary.link = link;
boundary.parentBoundary = currentBoundaryParse;
boundary.wrap = autoWrap();
parentBoundaryParse = currentBoundaryParse;
currentBoundaryParse = alias;
boundaryParseStack.push(parentBoundaryParse);
};
//alias, label, ?type, ?descr, ?sprite, ?tags, $link
export const addDeploymentNode = function (
nodeType,
alias,
label,
type,
descr,
sprite,
tags,
link
) {
// if (parentBoundary === null) return;
// Don't allow label nulling
if (alias === null || label === null) return;
let boundary = {};
const old = boundarys.find((boundary) => boundary.alias === alias);
if (old && alias === old.alias) {
boundary = old;
} else {
boundary.alias = alias;
boundarys.push(boundary);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
boundary.label = { text: '' };
} else {
boundary.label = { text: label };
}
if (type === undefined || type === null) {
boundary.type = { text: 'node' };
} else {
boundary.type = { text: type };
}
if (descr === undefined || descr === null) {
boundary.descr = { text: '' };
} else {
boundary.descr = { text: type };
}
boundary.tags = tags;
boundary.link = link;
boundary.nodeType = nodeType;
boundary.parentBoundary = currentBoundaryParse;
boundary.wrap = autoWrap();
parentBoundaryParse = currentBoundaryParse;
currentBoundaryParse = alias;
@ -173,18 +348,18 @@ export const getParentBoundaryParse = function () {
return parentBoundaryParse;
};
export const getPersonOrSystemArray = function (parentBoundary) {
if (parentBoundary === undefined || parentBoundary === null) return personOrSystemArray;
export const getC4ShapeArray = function (parentBoundary) {
if (parentBoundary === undefined || parentBoundary === null) return c4ShapeArray;
else
return personOrSystemArray.filter((personOrSystem) => {
return c4ShapeArray.filter((personOrSystem) => {
return personOrSystem.parentBoundary === parentBoundary;
});
};
export const getPersonOrSystem = function (alias) {
return personOrSystemArray.find((personOrSystem) => personOrSystem.alias === alias);
export const getC4Shape = function (alias) {
return c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
};
export const getPersonOrSystemKeys = function (parentBoundary) {
return Object.keys(getPersonOrSystemArray(parentBoundary));
export const getC4ShapeKeys = function (parentBoundary) {
return Object.keys(getC4ShapeArray(parentBoundary));
};
export const getBoundarys = function (parentBoundary) {
@ -209,12 +384,12 @@ export const autoWrap = function () {
};
export const clear = function () {
personOrSystemArray = [];
c4ShapeArray = [];
boundarys = [
{
alias: 'global',
label: { text: 'global' },
type: 'global',
type: { text: 'global' },
tags: null,
link: null,
parentBoundary: '',
@ -279,14 +454,18 @@ const getAccDescription = function () {
export default {
addPersonOrSystem,
addBoundary,
addPersonOrSystemBoundary,
addContainer,
addContainerBoundary,
addComponent,
addDeploymentNode,
popBoundaryParseStack,
addRel,
autoWrap,
setWrap,
getPersonOrSystemArray,
getPersonOrSystem,
getPersonOrSystemKeys,
getC4ShapeArray,
getC4Shape,
getC4ShapeKeys,
getBoundarys,
getCurrentBoundaryParse,
getParentBoundaryParse,

View File

@ -36,6 +36,7 @@ class Bounds {
this.nextData.stopx = undefined;
this.nextData.starty = undefined;
this.nextData.stopy = undefined;
this.nextData.cnt = 0;
setConf(parser.yy.getConfig());
}
@ -56,17 +57,26 @@ class Bounds {
}
insert(c4Shape) {
let _startx = this.nextData.stopx + c4Shape.margin * 2;
this.nextData.cnt = this.nextData.cnt + 1;
let _startx =
this.nextData.startx === this.nextData.stopx
? this.nextData.stopx + c4Shape.margin
: this.nextData.stopx + c4Shape.margin * 2;
let _stopx = _startx + c4Shape.width;
let _starty = this.nextData.starty + c4Shape.margin * 2;
let _stopy = _starty + c4Shape.height;
if (_startx >= this.data.widthLimit || _stopx >= this.data.widthLimit) {
_startx = this.nextData.startx + c4Shape.margin * 2 + conf.nextLinePaddingX;
if (
_startx >= this.data.widthLimit ||
_stopx >= this.data.widthLimit ||
this.nextData.cnt > conf.c4ShapeInRow
) {
_startx = this.nextData.startx + c4Shape.margin + conf.nextLinePaddingX;
_starty = this.nextData.stopy + c4Shape.margin * 2;
this.nextData.stopx = _stopx = _startx + c4Shape.width;
this.nextData.starty = this.nextData.stopy;
this.nextData.stopy = _stopy = _starty + c4Shape.height;
this.nextData.cnt = 1;
}
c4Shape.x = _startx;
@ -84,6 +94,7 @@ class Bounds {
}
init() {
this.name = '';
this.data = {
startx: undefined,
stopx: undefined,
@ -91,6 +102,13 @@ class Bounds {
stopy: undefined,
widthLimit: undefined,
};
this.nextData = {
startx: undefined,
stopx: undefined,
starty: undefined,
stopy: undefined,
cnt: 0,
};
setConf(parser.yy.getConfig());
}
@ -100,19 +118,25 @@ class Bounds {
}
}
const personFont = (cnf) => {
return {
fontFamily: cnf.personFontFamily,
fontSize: cnf.personFontSize,
fontWeight: cnf.personFontWeight,
};
export const setConf = function (cnf) {
assignWithDepth(conf, cnf);
if (cnf.fontFamily) {
conf.personFontFamily = conf.systemFontFamily = conf.messageFontFamily = cnf.fontFamily;
}
if (cnf.fontSize) {
conf.personFontSize = conf.systemFontSize = conf.messageFontSize = cnf.fontSize;
}
if (cnf.fontWeight) {
conf.personFontWeight = conf.systemFontWeight = conf.messageFontWeight = cnf.fontWeight;
}
};
const systemFont = (cnf) => {
const c4ShapeFont = (cnf, typeC4Shape) => {
return {
fontFamily: cnf.systemFontFamily,
fontSize: cnf.systemFontSize,
fontWeight: cnf.systemFontWeight,
fontFamily: cnf[typeC4Shape + 'FontFamily'],
fontSize: cnf[typeC4Shape + 'FontSize'],
fontWeight: cnf[typeC4Shape + 'FontWeight'],
};
};
@ -139,16 +163,18 @@ const messageFont = (cnf) => {
* @param textConf
* @param textLimitWidth
*/
function setC4ShapeText(textType, c4Shape, c4ShapeTextWrap, textConf, textLimitWidth) {
function calcC4ShapeTextWH(textType, c4Shape, c4ShapeTextWrap, textConf, textLimitWidth) {
if (!c4Shape[textType].width) {
if (c4ShapeTextWrap) {
c4Shape[textType].text = wrapLabel(c4Shape[textType].text, textLimitWidth, textConf);
c4Shape[textType].labelLines = c4Shape[textType].text.split(common.lineBreakRegex).length;
c4Shape[textType].textLines = c4Shape[textType].text.split(common.lineBreakRegex).length;
// c4Shape[textType].width = calculateTextWidth(c4Shape[textType].text, textConf);
c4Shape[textType].width = textLimitWidth;
c4Shape[textType].height = c4Shape[textType].labelLines * (textConf.fontSize + 2);
// c4Shape[textType].height = c4Shape[textType].textLines * textConf.fontSize;
c4Shape[textType].height = calculateTextHeight(c4Shape[textType].text, textConf);
} else {
let lines = c4Shape[textType].text.split(common.lineBreakRegex);
c4Shape[textType].labelLines = lines.length;
c4Shape[textType].textLines = lines.length;
let lineHeight = 0;
c4Shape[textType].height = 0;
c4Shape[textType].width = 0;
@ -160,7 +186,7 @@ function setC4ShapeText(textType, c4Shape, c4ShapeTextWrap, textConf, textLimitW
lineHeight = calculateTextHeight(lines[i], textConf);
c4Shape[textType].height = c4Shape[textType].height + lineHeight;
}
// c4Shapes[textType].height = c4Shapes[textType].labelLines * textConf.fontSize;
// c4Shapes[textType].height = c4Shapes[textType].textLines * textConf.fontSize;
}
}
}
@ -178,110 +204,102 @@ export const drawBoundary = function (diagram, boundary, bounds) {
boundaryLabelConf.fontSize = boundaryLabelConf.fontSize + 2;
boundaryLabelConf.fontWeight = 'bold';
let textLimitWidth = calculateTextWidth(boundary.label.text, boundaryLabelConf);
setC4ShapeText('label', boundary, boundaryTextWrap, boundaryLabelConf, textLimitWidth);
calcC4ShapeTextWH('label', boundary, boundaryTextWrap, boundaryLabelConf, textLimitWidth);
svgDraw.drawBoundary(diagram, boundary, conf);
};
export const drawPersonOrSystemArray = function (
currentBounds,
diagram,
personOrSystemArray,
personOrSystemKeys
) {
// Draw the personOrSystemArray
export const drawC4ShapeArray = function (currentBounds, diagram, c4ShapeArray, c4ShapeKeys) {
// Upper Y is relative point
let Y = 0;
// Draw the c4ShapeArray
for (let i = 0; i < c4ShapeKeys.length; i++) {
Y = 0;
const c4Shape = c4ShapeArray[c4ShapeKeys[i]];
// let prevWidth = currentBounds.data.stopx;
// let prevMarginX = conf.c4ShapeMargin;
// let prevMarginY = conf.c4ShapeMargin;
// let maxHeight = currentBounds.data.starty;
// calc c4 shape type width and height
for (let i = 0; i < personOrSystemKeys.length; i++) {
const personOrSystem = personOrSystemArray[personOrSystemKeys[i]];
let c4ShapeTypeConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
c4ShapeTypeConf.fontSize = c4ShapeTypeConf.fontSize - 2;
c4Shape.typeC4Shape.width = calculateTextWidth(
'<<' + c4Shape.typeC4Shape.text + '>>',
c4ShapeTypeConf
);
c4Shape.typeC4Shape.height = c4ShapeTypeConf.fontSize + 2;
c4Shape.typeC4Shape.Y = conf.c4ShapePadding;
Y = c4Shape.typeC4Shape.Y + c4Shape.typeC4Shape.height - 4;
let imageWidth = 0,
imageHeight = 0;
switch (personOrSystem.type) {
// set image width and height c4Shape.x + c4Shape.width / 2 - 24, c4Shape.y + 28
// let imageWidth = 0,
// imageHeight = 0,
// imageY = 0;
//
c4Shape.image = { width: 0, height: 0, Y: 0 };
switch (c4Shape.typeC4Shape.text) {
case 'person':
case 'external_person':
imageWidth = 48;
imageHeight = 48;
c4Shape.image.width = 48;
c4Shape.image.height = 48;
c4Shape.image.Y = Y;
Y = c4Shape.image.Y + c4Shape.image.height;
break;
}
if (!personOrSystem.typeLabelWidth) {
let personOrSystemTypeConf = personFont(conf);
personOrSystemTypeConf.fontSize = personOrSystemTypeConf.fontSize - 2;
personOrSystem.typeLabelWidth = calculateTextWidth(
'<<' + personOrSystem.type + '>>',
personOrSystemTypeConf
);
personOrSystem.typeLabelHeight = personOrSystemTypeConf.fontSize + 2;
switch (personOrSystem.type) {
case 'system_db':
case 'external_system_db':
personOrSystem.typeLabelY = conf.c4ShapePadding;
break;
default:
personOrSystem.typeLabelY = conf.c4ShapePadding - 5;
break;
}
if (c4Shape.sprite) {
c4Shape.image.width = 48;
c4Shape.image.height = 48;
c4Shape.image.Y = Y;
Y = c4Shape.image.Y + c4Shape.image.height;
}
let personOrSystemTextWrap = personOrSystem.wrap && conf.wrap;
// Y = conf.c4ShapePadding + c4Shape.image.height;
let c4ShapeTextWrap = c4Shape.wrap && conf.wrap;
let textLimitWidth = conf.width - conf.c4ShapePadding * 2;
let personOrSystemLabelConf = personFont(conf);
personOrSystemLabelConf.fontSize = personOrSystemLabelConf.fontSize + 2;
personOrSystemLabelConf.fontWeight = 'bold';
let c4ShapeLabelConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
c4ShapeLabelConf.fontSize = c4ShapeLabelConf.fontSize + 2;
c4ShapeLabelConf.fontWeight = 'bold';
calcC4ShapeTextWH('label', c4Shape, c4ShapeTextWrap, c4ShapeLabelConf, textLimitWidth);
c4Shape['label'].Y = Y + 8;
Y = c4Shape['label'].Y + c4Shape['label'].height;
setC4ShapeText(
'label',
personOrSystem,
personOrSystemTextWrap,
personOrSystemLabelConf,
textLimitWidth
);
personOrSystem['label'].Y =
conf.c4ShapePadding + personOrSystem.typeLabelHeight + imageHeight + 10;
if (c4Shape.type && c4Shape.type.text !== '') {
c4Shape.type.text = '[' + c4Shape.type.text + ']';
let c4ShapeTypeConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
calcC4ShapeTextWH('type', c4Shape, c4ShapeTextWrap, c4ShapeTypeConf, textLimitWidth);
c4Shape['type'].Y = Y + 5;
Y = c4Shape['type'].Y + c4Shape['type'].height;
} else if (c4Shape.techn && c4Shape.techn.text !== '') {
c4Shape.techn.text = '[' + c4Shape.techn.text + ']';
let c4ShapeTechnConf = c4ShapeFont(conf, c4Shape.techn.text);
calcC4ShapeTextWH('techn', c4Shape, c4ShapeTextWrap, c4ShapeTechnConf, textLimitWidth);
c4Shape['techn'].Y = Y + 5;
Y = c4Shape['techn'].Y + c4Shape['techn'].height;
}
let personOrSystemDescrConf = personFont(conf);
setC4ShapeText(
'descr',
personOrSystem,
personOrSystemTextWrap,
personOrSystemDescrConf,
textLimitWidth
);
personOrSystem['descr'].Y =
conf.c4ShapePadding +
personOrSystem.typeLabelHeight +
imageHeight +
5 +
personOrSystem.label.height +
conf.personFontSize +
2;
let rectHeight = Y;
let rectWidth = c4Shape.label.width;
// Add some rendering data to the object
let rectWidth =
Math.max(personOrSystem.label.width, personOrSystem.descr.width) + conf.c4ShapePadding * 2;
let rectHeight =
conf.c4ShapePadding +
personOrSystem.typeLabelHeight +
imageHeight +
personOrSystem.label.height +
conf.personFontSize +
2 +
personOrSystem.descr.height;
if (c4Shape.descr && c4Shape.descr.text !== '') {
let c4ShapeDescrConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
calcC4ShapeTextWH('descr', c4Shape, c4ShapeTextWrap, c4ShapeDescrConf, textLimitWidth);
c4Shape['descr'].Y = Y + 20;
Y = c4Shape['descr'].Y + c4Shape['descr'].height;
personOrSystem.width = Math.max(personOrSystem.width || conf.width, rectWidth, conf.width);
personOrSystem.height = Math.max(personOrSystem.height || conf.height, rectHeight, conf.height);
personOrSystem.margin = personOrSystem.margin || conf.c4ShapeMargin;
rectWidth = Math.max(c4Shape.label.width, c4Shape.descr.width);
rectHeight = Y - c4Shape['descr'].textLines * 5;
}
currentBounds.insert(personOrSystem);
rectWidth = rectWidth + conf.c4ShapePadding;
// let rectHeight =
const height = svgDraw.drawPersonOrSystem(diagram, personOrSystem, conf);
c4Shape.width = Math.max(c4Shape.width || conf.width, rectWidth, conf.width);
c4Shape.height = Math.max(c4Shape.height || conf.height, rectHeight, conf.height);
c4Shape.margin = c4Shape.margin || conf.c4ShapeMargin;
currentBounds.insert(c4Shape);
const height = svgDraw.drawC4Shape(diagram, c4Shape, conf);
}
currentBounds.bumpLastMargin(conf.c4ShapeMargin);
@ -391,20 +409,24 @@ let getIntersectPoints = function (fromNode, endNode) {
};
export const drawRels = function (diagram, rels, getC4ShapeObj) {
let i = 0;
for (let rel of rels) {
i = i + 1;
let relTextWrap = rel.wrap && conf.wrap;
let relConf = messageFont(conf);
let diagramType = parser.yy.getC4Type();
if (diagramType === 'C4Dynamic') rel.label.text = i + ': ' + rel.label.text;
let textLimitWidth = calculateTextWidth(rel.label.text, relConf);
setC4ShapeText('label', rel, relTextWrap, relConf, textLimitWidth);
calcC4ShapeTextWH('label', rel, relTextWrap, relConf, textLimitWidth);
if (rel.techn && rel.techn.text !== '') {
textLimitWidth = calculateTextWidth(rel.techn.text, relConf);
setC4ShapeText('techn', rel, relTextWrap, relConf, textLimitWidth);
calcC4ShapeTextWH('techn', rel, relTextWrap, relConf, textLimitWidth);
}
if (rel.descr && rel.descr.text !== '') {
textLimitWidth = calculateTextWidth(rel.descr.text, relConf);
setC4ShapeText('descr', rel, relTextWrap, relConf, textLimitWidth);
calcC4ShapeTextWH('descr', rel, relTextWrap, relConf, textLimitWidth);
}
let fromNode = getC4ShapeObj(rel.from);
@ -416,20 +438,6 @@ export const drawRels = function (diagram, rels, getC4ShapeObj) {
svgDraw.drawRels(diagram, rels, conf);
};
export const setConf = function (cnf) {
assignWithDepth(conf, cnf);
if (cnf.fontFamily) {
conf.personFontFamily = conf.systemFontFamily = conf.messageFontFamily = cnf.fontFamily;
}
if (cnf.fontSize) {
conf.personFontSize = conf.systemFontSize = conf.messageFontSize = cnf.fontSize;
}
if (cnf.fontWeight) {
conf.personFontWeight = conf.systemFontWeight = conf.messageFontWeight = cnf.fontWeight;
}
};
/**
* @param diagram
* @param parentBoundaryAlias
@ -439,16 +447,70 @@ export const setConf = function (cnf) {
function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentBoundarys) {
let currentBounds = new Bounds();
// Calculate the width limit of the boundar. label/type 的长度,
currentBounds.data.widthLimit = Math.min(
conf.width * conf.c4ShapeInRow + conf.c4ShapeMargin * (conf.c4ShapeInRow + 1),
parentBounds.data.widthLimit / Math.min(conf.c4BoundaryInRow, currentBoundarys.length)
);
currentBounds.data.widthLimit =
parentBounds.data.widthLimit / Math.min(conf.c4BoundaryInRow, currentBoundarys.length);
// Math.min(
// conf.width * conf.c4ShapeInRow + conf.c4ShapeMargin * conf.c4ShapeInRow * 2,
// parentBounds.data.widthLimit / Math.min(conf.c4BoundaryInRow, currentBoundarys.length)
// );
for (let i = 0; i < currentBoundarys.length; i++) {
let currentBoundary = currentBoundarys[i];
if (i == 0) {
let Y = 0;
currentBoundary.image = { width: 0, height: 0, Y: 0 };
if (currentBoundary.sprite) {
currentBoundary.image.width = 48;
currentBoundary.image.height = 48;
currentBoundary.image.Y = Y;
Y = currentBoundary.image.Y + currentBoundary.image.height;
}
let currentBoundaryTextWrap = currentBoundary.wrap && conf.wrap;
let currentBoundaryLabelConf = boundaryFont(conf);
currentBoundaryLabelConf.fontSize = currentBoundaryLabelConf.fontSize + 2;
currentBoundaryLabelConf.fontWeight = 'bold';
calcC4ShapeTextWH(
'label',
currentBoundary,
currentBoundaryTextWrap,
currentBoundaryLabelConf,
currentBounds.data.widthLimit
);
currentBoundary['label'].Y = Y + 8;
Y = currentBoundary['label'].Y + currentBoundary['label'].height;
if (currentBoundary.type && currentBoundary.type.text !== '') {
currentBoundary.type.text = '[' + currentBoundary.type.text + ']';
let currentBoundaryTypeConf = boundaryFont(conf);
calcC4ShapeTextWH(
'type',
currentBoundary,
currentBoundaryTextWrap,
currentBoundaryTypeConf,
currentBounds.data.widthLimit
);
currentBoundary['type'].Y = Y + 5;
Y = currentBoundary['type'].Y + currentBoundary['type'].height;
}
if (currentBoundary.descr && currentBoundary.descr.text !== '') {
let currentBoundaryDescrConf = boundaryFont(conf);
currentBoundaryDescrConf.fontSize = currentBoundaryDescrConf.fontSize - 2;
calcC4ShapeTextWH(
'descr',
currentBoundary,
currentBoundaryTextWrap,
currentBoundaryDescrConf,
currentBounds.data.widthLimit
);
currentBoundary['descr'].Y = Y + 20;
Y = currentBoundary['descr'].Y + currentBoundary['descr'].height;
}
if (i == 0 || i % conf.c4BoundaryInRow === 0) {
// Calculate the drawing start point of the currentBoundarys.
let _x = parentBounds.data.startx + conf.diagramMarginX;
let _y = parentBounds.data.stopy + conf.diagramMarginY;
let _y = parentBounds.data.stopy + conf.diagramMarginY + Y;
currentBounds.setData(_x, _x, _y, _y);
} else {
@ -462,11 +524,11 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
currentBounds.setData(_x, _x, _y, _y);
}
currentBounds.name = currentBoundary.alias;
let currentPersonOrSystemArray = parser.yy.getPersonOrSystemArray(currentBoundary.alias);
let currentPersonOrSystemKeys = parser.yy.getPersonOrSystemKeys(currentBoundary.alias);
let currentPersonOrSystemArray = parser.yy.getC4ShapeArray(currentBoundary.alias);
let currentPersonOrSystemKeys = parser.yy.getC4ShapeKeys(currentBoundary.alias);
if (currentPersonOrSystemKeys.length > 0) {
drawPersonOrSystemArray(
drawC4ShapeArray(
currentBounds,
diagram,
currentPersonOrSystemArray,
@ -545,11 +607,11 @@ export const draw = function (text, id) {
const title = parser.yy.getTitle();
const c4type = parser.yy.getC4Type();
let currentBoundarys = parser.yy.getBoundarys('');
switch (c4type) {
case 'C4Context':
drawInsideBoundary(diagram, '', screenBounds, currentBoundarys);
break;
}
// switch (c4type) {
// case 'C4Context':
drawInsideBoundary(diagram, '', screenBounds, currentBoundarys);
// break;
// }
// The arrow head definition is attached to the svg once
svgDraw.insertArrowHead(diagram);
@ -557,7 +619,7 @@ export const draw = function (text, id) {
svgDraw.insertArrowCrossHead(diagram);
svgDraw.insertArrowFilledHead(diagram);
drawRels(diagram, parser.yy.getRels(), parser.yy.getPersonOrSystem);
drawRels(diagram, parser.yy.getRels(), parser.yy.getC4Shape);
screenBounds.data.stopx = globalBoundaryMaxX;
screenBounds.data.stopy = globalBoundaryMaxY;
@ -578,7 +640,7 @@ export const draw = function (text, id) {
.append('text')
.text(title)
.attr('x', (box.stopx - box.startx) / 2 - 4 * conf.diagramMarginX)
.attr('y', -25);
.attr('y', box.starty + conf.diagramMarginY);
}
configureSvgSize(diagram, height, width, conf.useMaxWidth);
@ -601,7 +663,7 @@ export const draw = function (text, id) {
};
export default {
drawPersonOrSystemArray,
drawPersonOrSystemArray: drawC4ShapeArray,
drawBoundary,
setConf,
draw,

View File

@ -48,7 +48,6 @@
%x index
/* Deployment diagram */
%x deployment_node
%x node
%x node_l
%x node_r
@ -56,10 +55,11 @@
/* Relationship Types */
%x rel
%x rel_bi
%x rel_up
%x rel_down
%x rel_left
%x rel_right
%x rel_u
%x rel_d
%x rel_l
%x rel_r
%x rel_b
%x attribute
%x string
@ -105,18 +105,45 @@
"Enterprise_Boundary" { this.begin("enterprise_boundary"); console.log('begin enterprise_boundary'); return 'ENTERPRISE_BOUNDARY';}
"System_Boundary" { this.begin("system_boundary"); console.log('begin system_boundary'); return 'SYSTEM_BOUNDARY';}
"ContainerQueue_Ext" { this.begin("container_ext_queue"); console.log('begin container_ext_queue'); return 'CONTAINER_EXT_QUEUE';}
"ContainerDb_Ext" { this.begin("container_ext_db"); console.log('begin container_ext_db'); return 'CONTAINER_EXT_DB';}
"Container_Ext" { this.begin("container_ext"); console.log('begin container_ext'); return 'CONTAINER_EXT';}
"ContainerQueue" { this.begin("container_queue"); console.log('begin container_queue'); return 'CONTAINER_QUEUE';}
"ContainerDb" { this.begin("container_db"); console.log('begin container_db'); return 'CONTAINER_DB';}
"Container" { this.begin("container"); console.log('begin container'); return 'CONTAINER';}
"Container_Boundary" { this.begin("container_boundary"); console.log('begin container_boundary'); return 'CONTAINER_BOUNDARY';}
"ComponentQueue_Ext" { this.begin("component_ext_queue"); console.log('begin component_ext_queue'); return 'COMPONENT_EXT_QUEUE';}
"ComponentDb_Ext" { this.begin("component_ext_db"); console.log('begin component_ext_db'); return 'COMPONENT_EXT_DB';}
"Component_Ext" { this.begin("component_ext"); console.log('begin component_ext'); return 'COMPONENT_EXT';}
"ComponentQueue" { this.begin("component_queue"); console.log('begin component_queue'); return 'COMPONENT_QUEUE';}
"ComponentDb" { this.begin("component_db"); console.log('begin component_db'); return 'COMPONENT_DB';}
"Component" { this.begin("component"); console.log('begin component'); return 'COMPONENT';}
"Deployment_Node" { this.begin("node"); console.log('begin node'); return 'NODE';}
"Node" { this.begin("node"); console.log('begin node'); return 'NODE';}
"Node_L" { this.begin("node_l"); console.log('begin node_l'); return 'NODE_L';}
"Node_R" { this.begin("node_r"); console.log('begin node_r'); return 'NODE_R';}
"Rel" { this.begin("rel"); console.log('begin rel'); return 'REL';}
"BiRel" { this.begin("birel"); console.log('begin birel'); return 'BIREL';}
"Rel_U|Rel_Up" { this.begin("rel_u"); console.log('begin rel_u'); return 'REL_U';}
"Rel_D|Rel_Down" { this.begin("rel_d"); console.log('begin rel_d'); return 'REL_D';}
"Rel_L|Rel_Left" { this.begin("rel_l"); console.log('begin rel_l'); return 'REL_L';}
"Rel_R|Rel_Right" { this.begin("rel_r"); console.log('begin rel_r'); return 'REL_R';}
"Rel_Up" { this.begin("rel_u"); console.log('begin rel_u'); return 'REL_U';}
"Rel_U" { this.begin("rel_u"); console.log('begin rel_u'); return 'REL_U';}
"Rel_Down" { this.begin("rel_d"); console.log('begin rel_d'); return 'REL_D';}
"Rel_D" { this.begin("rel_d"); console.log('begin rel_d'); return 'REL_D';}
"Rel_Left" { this.begin("rel_l"); console.log('begin rel_l'); return 'REL_L';}
"Rel_L" { this.begin("rel_l"); console.log('begin rel_l'); return 'REL_L';}
"Rel_Right" { this.begin("rel_r"); console.log('begin rel_r'); return 'REL_R';}
"Rel_R" { this.begin("rel_r"); console.log('begin rel_r'); return 'REL_R';}
"Rel_Back" { this.begin("rel_b"); console.log('begin rel_b'); return 'REL_B';}
"RelIndex" { this.begin("rel_index"); console.log('begin rel_index'); return 'REL_INDEX';}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,rel,birel,rel_u,rel_d,rel_l,rel_r><<EOF>> return "EOF_IN_STRUCT";
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,rel,birel,rel_u,rel_d,rel_l,rel_r>[(][ ]*[,] { console.log('begin attribute with ATTRIBUTE_EMPTY'); this.begin("attribute"); return "ATTRIBUTE_EMPTY";}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,rel,birel,rel_u,rel_d,rel_l,rel_r>[(] { console.log('begin attribute'); this.begin("attribute"); }
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,rel,birel,rel_u,rel_d,rel_l,rel_r,attribute>[)] { console.log('STOP attribute'); this.popState();console.log('STOP diagram'); this.popState();}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index><<EOF>> return "EOF_IN_STRUCT";
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index>[(][ ]*[,] { console.log('begin attribute with ATTRIBUTE_EMPTY'); this.begin("attribute"); return "ATTRIBUTE_EMPTY";}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index>[(] { console.log('begin attribute'); this.begin("attribute"); }
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,attribute>[)] { console.log('STOP attribute'); this.popState();console.log('STOP diagram'); this.popState();}
<attribute>",," { console.log(',,'); return 'ATTRIBUTE_EMPTY';}
<attribute>"," { console.log(','); }
@ -221,9 +248,13 @@ boundaryStartStatement
;
boundaryStart
: ENTERPRISE_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'ENTERPRISE'); yy.addBoundary(...$2); $$=$2;}
| SYSTEM_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'ENTERPRISE'); yy.addBoundary(...$2); $$=$2;}
| BOUNDARY attributes {console.log($1,JSON.stringify($2)); yy.addBoundary(...$2); $$=$2;}
: ENTERPRISE_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| SYSTEM_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| BOUNDARY attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| CONTAINER_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'CONTAINER'); yy.addContainerBoundary(...$2); $$=$2;}
| NODE attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('node', ...$2); $$=$2;}
| NODE_L attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('nodeL', ...$2); $$=$2;}
| NODE_R attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('nodeR', ...$2); $$=$2;}
;
boundaryStopStatement
@ -245,6 +276,18 @@ diagramStatement
| SYSTEM_EXT attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system', ...$2); $$=$2;}
| SYSTEM_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system_db', ...$2); $$=$2;}
| SYSTEM_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system_queue', ...$2); $$=$2;}
| CONTAINER attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container', ...$2); $$=$2;}
| CONTAINER_DB attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container_db', ...$2); $$=$2;}
| CONTAINER_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container_queue', ...$2); $$=$2;}
| CONTAINER_EXT attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container', ...$2); $$=$2;}
| CONTAINER_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container_db', ...$2); $$=$2;}
| CONTAINER_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container_queue', ...$2); $$=$2;}
| COMPONENT attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component', ...$2); $$=$2;}
| COMPONENT_DB attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component_db', ...$2); $$=$2;}
| COMPONENT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component_queue', ...$2); $$=$2;}
| COMPONENT_EXT attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component', ...$2); $$=$2;}
| COMPONENT_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component_db', ...$2); $$=$2;}
| COMPONENT_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component_queue', ...$2); $$=$2;}
| boundaryStatement
| REL attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel', ...$2); $$=$2;}
| BIREL attributes {console.log($1,JSON.stringify($2)); yy.addRel('birel', ...$2); $$=$2;}
@ -252,6 +295,8 @@ diagramStatement
| REL_D attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_d', ...$2); $$=$2;}
| REL_L attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_l', ...$2); $$=$2;}
| REL_R attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_r', ...$2); $$=$2;}
| REL_B attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_b', ...$2); $$=$2;}
| REL_INDEX attributes {console.log($1,JSON.stringify($2)); $2.splice(0, 1); yy.addRel('rel', ...$2); $$=$2;}
;
attributes

View File

@ -227,8 +227,9 @@ export const drawRels = (elem, rels, conf) => {
line.attr('stroke-width', '1');
line.attr('stroke', '#444444');
line.style('fill', 'none');
line.attr('marker-end', 'url(' + url + '#arrowhead)');
if (rel.type === 'birel') line.attr('marker-start', 'url(' + url + '#arrowend)');
if (rel.type !== 'rel_b') line.attr('marker-end', 'url(' + url + '#arrowhead)');
if (rel.type === 'birel' || rel.type === 'rel_b')
line.attr('marker-start', 'url(' + url + '#arrowend)');
i = -1;
} else {
let line = relsElem.append('path');
@ -250,9 +251,10 @@ export const drawRels = (elem, rels, conf) => {
.replaceAll('controly', rel.startPoint.y + (rel.endPoint.y - rel.startPoint.y) / 2)
.replaceAll('stopx', rel.endPoint.x)
.replaceAll('stopy', rel.endPoint.y)
)
.attr('marker-end', 'url(' + url + '#arrowhead)');
if (rel.type === 'birel') line.attr('marker-start', 'url(' + url + '#arrowend)');
);
if (rel.type !== 'rel_b') line.attr('marker-end', 'url(' + url + '#arrowhead)');
if (rel.type === 'birel' || rel.type === 'rel_b')
line.attr('marker-start', 'url(' + url + '#arrowend)');
}
let messageConf = conf.messageFont();
@ -297,6 +299,8 @@ export const drawRels = (elem, rels, conf) => {
const drawBoundary = function (elem, boundary, conf) {
const boundaryElem = elem.append('g');
let attrsValue = { 'stroke-width': 1.0, 'stroke-dasharray': '7.0,7.0' };
if (boundary.nodeType) attrsValue = { 'stroke-width': 1.0 };
let rectData = {
x: boundary.x,
y: boundary.y,
@ -306,11 +310,12 @@ const drawBoundary = function (elem, boundary, conf) {
height: boundary.height,
rx: 2.5,
ry: 2.5,
attrs: { 'stroke-width': 1.0, 'stroke-dasharray': '7.0,7.0' },
attrs: attrsValue,
};
drawRect(boundaryElem, rectData);
// draw lable
let boundaryConf = conf.boundaryFont();
boundaryConf.fontWeight = 'bold';
boundaryConf.fontSize = boundaryConf.fontSize + 2;
@ -318,33 +323,51 @@ const drawBoundary = function (elem, boundary, conf) {
boundary.label.text,
boundaryElem,
boundary.x,
boundary.y + boundary.label.y,
boundary.y + boundary.label.Y,
boundary.width,
boundary.height,
{ fill: '#444444' },
boundaryConf
);
boundaryConf = conf.boundaryFont();
boundaryConf.fontSize = boundaryConf.fontSize - 2;
_drawTextCandidateFunc(conf)(
'[' + boundary.type + ']',
boundaryElem,
boundary.x,
boundary.y + boundary.label.y + boundaryConf.fontSize + 8,
boundary.width,
boundary.height,
{ fill: '#444444' },
boundaryConf
);
// draw type
if (boundary.type && boundary.type.text !== '') {
boundaryConf = conf.boundaryFont();
_drawTextCandidateFunc(conf)(
boundary.type.text,
boundaryElem,
boundary.x,
boundary.y + boundary.type.Y,
boundary.width,
boundary.height,
{ fill: '#444444' },
boundaryConf
);
}
// draw descr
if (boundary.descr && boundary.descr.text !== '') {
boundaryConf = conf.boundaryFont();
boundaryConf.fontSize = boundaryConf.fontSize - 2;
_drawTextCandidateFunc(conf)(
boundary.descr.text,
boundaryElem,
boundary.x,
boundary.y + boundary.descr.Y,
boundary.width,
boundary.height,
{ fill: '#444444' },
boundaryConf
);
}
};
export const drawPersonOrSystem = function (elem, personOrSystem, conf) {
let fillColor = conf[personOrSystem.type + '_bg_color'];
let strokeColor = conf[personOrSystem.type + '_border_color'];
export const drawC4Shape = function (elem, c4Shape, conf) {
let fillColor = conf[c4Shape.typeC4Shape.text + '_bg_color'];
let strokeColor = conf[c4Shape.typeC4Shape.text + '_border_color'];
let personImg =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAACD0lEQVR4Xu2YoU4EMRCGT+4j8Ai8AhaH4QHgAUjQuFMECUgMIUgwJAgMhgQsAYUiJCiQIBBY+EITsjfTdme6V24v4c8vyGbb+ZjOtN0bNcvjQXmkH83WvYBWto6PLm6v7p7uH1/w2fXD+PBycX1Pv2l3IdDm/vn7x+dXQiAubRzoURa7gRZWd0iGRIiJbOnhnfYBQZNJjNbuyY2eJG8fkDE3bbG4ep6MHUAsgYxmE3nVs6VsBWJSGccsOlFPmLIViMzLOB7pCVO2AtHJMohH7Fh6zqitQK7m0rJvAVYgGcEpe//PLdDz65sM4pF9N7ICcXDKIB5Nv6j7tD0NoSdM2QrU9Gg0ewE1LqBhHR3BBdvj2vapnidjHxD/q6vd7Pvhr31AwcY8eXMTXAKECZZJFXuEq27aLgQK5uLMohCenGGuGewOxSjBvYBqeG6B+Nqiblggdjnc+ZXDy+FNFpFzw76O3UBAROuXh6FoiAcf5g9eTvUgzy0nWg6I8cXHRUpg5bOVBCo+KDpFajOf23GgPme7RSQ+lacIENUgJ6gg1k6HjgOlqnLqip4tEuhv0hNEMXUD0clyXE3p6pZA0S2nnvTlXwLJEZWlb7cTQH1+USgTN4VhAenm/wea1OCAOmqo6fE1WCb9WSKBah+rbUWPWAmE2Rvk0ApiB45eOyNAzU8xcTvj8KvkKEoOaIYeHNA3ZuygAvFMUO0AAAAASUVORK5CYII=';
switch (personOrSystem.type) {
switch (c4Shape.typeC4Shape.text) {
case 'person':
personImg =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAACD0lEQVR4Xu2YoU4EMRCGT+4j8Ai8AhaH4QHgAUjQuFMECUgMIUgwJAgMhgQsAYUiJCiQIBBY+EITsjfTdme6V24v4c8vyGbb+ZjOtN0bNcvjQXmkH83WvYBWto6PLm6v7p7uH1/w2fXD+PBycX1Pv2l3IdDm/vn7x+dXQiAubRzoURa7gRZWd0iGRIiJbOnhnfYBQZNJjNbuyY2eJG8fkDE3bbG4ep6MHUAsgYxmE3nVs6VsBWJSGccsOlFPmLIViMzLOB7pCVO2AtHJMohH7Fh6zqitQK7m0rJvAVYgGcEpe//PLdDz65sM4pF9N7ICcXDKIB5Nv6j7tD0NoSdM2QrU9Gg0ewE1LqBhHR3BBdvj2vapnidjHxD/q6vd7Pvhr31AwcY8eXMTXAKECZZJFXuEq27aLgQK5uLMohCenGGuGewOxSjBvYBqeG6B+Nqiblggdjnc+ZXDy+FNFpFzw76O3UBAROuXh6FoiAcf5g9eTvUgzy0nWg6I8cXHRUpg5bOVBCo+KDpFajOf23GgPme7RSQ+lacIENUgJ6gg1k6HjgOlqnLqip4tEuhv0hNEMXUD0clyXE3p6pZA0S2nnvTlXwLJEZWlb7cTQH1+USgTN4VhAenm/wea1OCAOmqo6fE1WCb9WSKBah+rbUWPWAmE2Rvk0ApiB45eOyNAzU8xcTvj8KvkKEoOaIYeHNA3ZuygAvFMUO0AAAAASUVORK5CYII=';
@ -355,29 +378,38 @@ export const drawPersonOrSystem = function (elem, personOrSystem, conf) {
break;
}
const personOrSystemElem = elem.append('g');
personOrSystemElem.attr('class', 'person-man');
const c4ShapeElem = elem.append('g');
c4ShapeElem.attr('class', 'person-man');
// <rect fill="#08427B" height="119.2188" rx="2.5" ry="2.5" style="stroke:#073B6F;stroke-width:0.5;" width="110" x="120" y="7"/>
// draw rect of c4Shape
const rect = getNoteRect();
switch (personOrSystem.type) {
switch (c4Shape.typeC4Shape.text) {
case 'person':
case 'external_person':
case 'system':
case 'external_system':
rect.x = personOrSystem.x;
rect.y = personOrSystem.y;
case 'container':
case 'external_container':
case 'component':
case 'external_component':
rect.x = c4Shape.x;
rect.y = c4Shape.y;
rect.fill = fillColor;
rect.width = personOrSystem.width;
rect.height = personOrSystem.height;
rect.width = c4Shape.width;
rect.height = c4Shape.height;
rect.style = 'stroke:' + strokeColor + ';stroke-width:0.5;';
rect.rx = 2.5;
rect.ry = 2.5;
drawRect(personOrSystemElem, rect);
drawRect(c4ShapeElem, rect);
break;
case 'system_db':
case 'external_system_db':
personOrSystemElem
case 'container_db':
case 'external_container_db':
case 'component_db':
case 'external_component_db':
c4ShapeElem
.append('path')
.attr('fill', fillColor)
.attr('stroke-width', '0.5')
@ -385,12 +417,12 @@ export const drawPersonOrSystem = function (elem, personOrSystem, conf) {
.attr(
'd',
'Mstartx,startyc0,-10 half,-10 half,-10c0,0 half,0 half,10l0,heightc0,10 -half,10 -half,10c0,0 -half,0 -half,-10l0,-height'
.replaceAll('startx', personOrSystem.x)
.replaceAll('starty', personOrSystem.y)
.replaceAll('half', personOrSystem.width / 2)
.replaceAll('height', personOrSystem.height)
.replaceAll('startx', c4Shape.x)
.replaceAll('starty', c4Shape.y)
.replaceAll('half', c4Shape.width / 2)
.replaceAll('height', c4Shape.height)
);
personOrSystemElem
c4ShapeElem
.append('path')
.attr('fill', 'none')
.attr('stroke-width', '0.5')
@ -398,14 +430,18 @@ export const drawPersonOrSystem = function (elem, personOrSystem, conf) {
.attr(
'd',
'Mstartx,startyc0,10 half,10 half,10c0,0 half,0 half,-10'
.replaceAll('startx', personOrSystem.x)
.replaceAll('starty', personOrSystem.y)
.replaceAll('half', personOrSystem.width / 2)
.replaceAll('startx', c4Shape.x)
.replaceAll('starty', c4Shape.y)
.replaceAll('half', c4Shape.width / 2)
);
break;
case 'system_queue':
case 'external_system_queue':
personOrSystemElem
case 'container_queue':
case 'external_container_queue':
case 'component_queue':
case 'external_component_queue':
c4ShapeElem
.append('path')
.attr('fill', fillColor)
.attr('stroke-width', '0.5')
@ -413,12 +449,12 @@ export const drawPersonOrSystem = function (elem, personOrSystem, conf) {
.attr(
'd',
'Mstartx,startylwidth,0c5,0 5,half 5,halfc0,0 0,half -5,halfl-width,0c-5,0 -5,-half -5,-halfc0,0 0,-half 5,-half'
.replaceAll('startx', personOrSystem.x)
.replaceAll('starty', personOrSystem.y)
.replaceAll('width', personOrSystem.width)
.replaceAll('half', personOrSystem.height / 2)
.replaceAll('startx', c4Shape.x)
.replaceAll('starty', c4Shape.y)
.replaceAll('width', c4Shape.width)
.replaceAll('half', c4Shape.height / 2)
);
personOrSystemElem
c4ShapeElem
.append('path')
.attr('fill', 'none')
.attr('stroke-width', '0.5')
@ -426,66 +462,100 @@ export const drawPersonOrSystem = function (elem, personOrSystem, conf) {
.attr(
'd',
'Mstartx,startyc-5,0 -5,half -5,halfc0,half 5,half 5,half'
.replaceAll('startx', personOrSystem.x + personOrSystem.width)
.replaceAll('starty', personOrSystem.y)
.replaceAll('half', personOrSystem.height / 2)
.replaceAll('startx', c4Shape.x + c4Shape.width)
.replaceAll('starty', c4Shape.y)
.replaceAll('half', c4Shape.height / 2)
);
break;
}
personOrSystemElem
// draw type of c4Shape
let c4ShapeFontConf = getC4ShapeFont(conf, c4Shape.typeC4Shape.text);
c4ShapeElem
.append('text')
.attr('fill', '#FFFFFF')
.attr('font-family', conf.personFontFamily)
.attr('font-size', conf.personFontSize - 2)
.attr('font-family', c4ShapeFontConf.fontFamily)
.attr('font-size', c4ShapeFontConf.fontSize - 2)
.attr('font-style', 'italic')
.attr('lengthAdjust', 'spacing')
.attr('textLength', personOrSystem.typeLabelWidth)
.attr('x', personOrSystem.x + personOrSystem.width / 2 - personOrSystem.typeLabelWidth / 2)
.attr('y', personOrSystem.y + personOrSystem.typeLabelY)
.text('<<' + personOrSystem.type + '>>');
.attr('textLength', c4Shape.typeC4Shape.width)
.attr('x', c4Shape.x + c4Shape.width / 2 - c4Shape.typeC4Shape.width / 2)
.attr('y', c4Shape.y + c4Shape.typeC4Shape.Y)
.text('<<' + c4Shape.typeC4Shape.text + '>>');
switch (personOrSystem.type) {
// draw image/sprite
switch (c4Shape.typeC4Shape.text) {
case 'person':
case 'external_person':
drawImage(
personOrSystemElem,
c4ShapeElem,
48,
48,
personOrSystem.x + personOrSystem.width / 2 - 24,
personOrSystem.y + 24,
c4Shape.x + c4Shape.width / 2 - 24,
c4Shape.y + c4Shape.image.Y,
personImg
);
break;
}
let personOrSystemConf = conf.personFont();
personOrSystemConf.fontWeight = 'bold';
personOrSystemConf.fontSize = personOrSystemConf.fontSize + 2;
// draw label
let textFontConf = conf[c4Shape.typeC4Shape.text + 'Font']();
textFontConf.fontWeight = 'bold';
textFontConf.fontSize = textFontConf.fontSize + 2;
_drawTextCandidateFunc(conf)(
personOrSystem.label.text,
personOrSystemElem,
personOrSystem.x,
personOrSystem.y + personOrSystem.label.Y,
personOrSystem.width,
personOrSystem.height,
c4Shape.label.text,
c4ShapeElem,
c4Shape.x,
c4Shape.y + c4Shape.label.Y,
c4Shape.width,
c4Shape.height,
{ fill: '#FFFFFF' },
personOrSystemConf
textFontConf
);
personOrSystemConf = conf.personFont();
_drawTextCandidateFunc(conf)(
personOrSystem.descr.text,
personOrSystemElem,
personOrSystem.x,
personOrSystem.y + personOrSystem.descr.Y,
personOrSystem.width,
personOrSystem.height,
{ fill: '#FFFFFF' },
personOrSystemConf
);
// draw techn/type
textFontConf = conf[c4Shape.typeC4Shape.text + 'Font']();
return personOrSystem.height;
if (c4Shape.thchn && c4Shape.thchn.text !== '') {
_drawTextCandidateFunc(conf)(
c4Shape.thchn.text,
c4ShapeElem,
c4Shape.x,
c4Shape.y + c4Shape.thchn.Y,
c4Shape.width,
c4Shape.height,
{ fill: '#FFFFFF', 'font-style': 'italic' },
textFontConf
);
} else if (c4Shape.type && c4Shape.type.text !== '') {
_drawTextCandidateFunc(conf)(
c4Shape.type.text,
c4ShapeElem,
c4Shape.x,
c4Shape.y + c4Shape.type.Y,
c4Shape.width,
c4Shape.height,
{ fill: '#FFFFFF', 'font-style': 'italic' },
textFontConf
);
}
// draw descr
if (c4Shape.descr && c4Shape.descr.text !== '') {
textFontConf = conf.personFont();
_drawTextCandidateFunc(conf)(
c4Shape.descr.text,
c4ShapeElem,
c4Shape.x,
c4Shape.y + c4Shape.descr.Y,
c4Shape.width,
c4Shape.height,
{ fill: '#FFFFFF' },
textFontConf
);
}
return c4Shape.height;
};
export const insertDatabaseIcon = function (elem) {
@ -672,6 +742,14 @@ export const getNoteRect = function () {
};
};
const getC4ShapeFont = (cnf, typeC4Shape) => {
return {
fontFamily: cnf[typeC4Shape + 'FontFamily'],
fontSize: cnf[typeC4Shape + 'FontSize'],
fontWeight: cnf[typeC4Shape + 'FontWeight'],
};
};
const _drawTextCandidateFunc = (function () {
/**
* @param {any} content
@ -713,16 +791,17 @@ const _drawTextCandidateFunc = (function () {
.attr('x', x + width / 2)
.attr('y', y)
.style('text-anchor', 'middle')
.attr('dominant-baseline', 'middle')
.style('font-size', fontSize)
.style('font-weight', fontWeight)
.style('font-family', fontFamily);
text
.append('tspan')
.attr('x', x + width / 2)
// .attr('x', x + width / 2)
.attr('dy', dy)
.text(lines[i]);
text.attr('y', y).attr('dominant-baseline', 'central').attr('alignment-baseline', 'central');
.text(lines[i])
// .attr('y', y + height / 2)
.attr('alignment-baseline', 'mathematical');
_setTextAttrs(text, textAttrs);
}
@ -787,14 +866,14 @@ export default {
drawText,
drawLabel,
drawBoundary,
drawPersonOrSystem,
drawC4Shape,
drawRels,
drawImage,
drawEmbeddedImage,
insertArrowHead,
insertArrowEnd,
insertArrowFilledHead,
insertSequenceNumber: insertDynamicNumber,
insertDynamicNumber,
insertArrowCrossHead,
insertDatabaseIcon,
insertComputerIcon,