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,