diff --git a/demos/index.html b/demos/index.html
index 1db4bf416..0abe627a7 100644
--- a/demos/index.html
+++ b/demos/index.html
@@ -23,32 +23,33 @@
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,
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")
+
+ 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")
+
+
+
+ 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")
+
+
+
+ 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")
+
+
+
+ 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,
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")
+
+
diff --git a/src/defaultConfig.js b/src/defaultConfig.js
index b2dead919..67a0b7d27 100644
--- a/src/defaultConfig.js
+++ b/src/defaultConfig.js
@@ -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',
},
};
diff --git a/src/diagrams/c4/c4Db.js b/src/diagrams/c4/c4Db.js
index d29d11c85..c483df287 100644
--- a/src/diagrams/c4/c4Db.js
+++ b/src/diagrams/c4/c4Db.js
@@ -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,
diff --git a/src/diagrams/c4/c4Renderer.js b/src/diagrams/c4/c4Renderer.js
index dba7172c9..d71e70e2e 100644
--- a/src/diagrams/c4/c4Renderer.js
+++ b/src/diagrams/c4/c4Renderer.js
@@ -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,
diff --git a/src/diagrams/c4/parser/c4Diagram.jison b/src/diagrams/c4/parser/c4Diagram.jison
index dd9672226..9b57e3cf1 100644
--- a/src/diagrams/c4/parser/c4Diagram.jison
+++ b/src/diagrams/c4/parser/c4Diagram.jison
@@ -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';}
-
-
<> return "EOF_IN_STRUCT";
-[(][ ]*[,] { console.log('begin attribute with ATTRIBUTE_EMPTY'); this.begin("attribute"); return "ATTRIBUTE_EMPTY";}
-[(] { console.log('begin attribute'); this.begin("attribute"); }
-[)] { console.log('STOP attribute'); this.popState();console.log('STOP diagram'); this.popState();}
+<> return "EOF_IN_STRUCT";
+[(][ ]*[,] { console.log('begin attribute with ATTRIBUTE_EMPTY'); this.begin("attribute"); return "ATTRIBUTE_EMPTY";}
+[(] { console.log('begin attribute'); this.begin("attribute"); }
+[)] { console.log('STOP attribute'); this.popState();console.log('STOP diagram'); this.popState();}
",," { console.log(',,'); return 'ATTRIBUTE_EMPTY';}
"," { 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
diff --git a/src/diagrams/c4/svgDraw.js b/src/diagrams/c4/svgDraw.js
index 7081d4e5b..fb3a276db 100644
--- a/src/diagrams/c4/svgDraw.js
+++ b/src/diagrams/c4/svgDraw.js
@@ -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');
//
+ // 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,