1 | import { p as parser, d as db, s as styles } from "./styles-b83b31c9.js";
|
2 | import { line, curveBasis, select } from "d3";
|
3 | import { layout } from "dagre-d3-es/src/dagre/index.js";
|
4 | import * as graphlib from "dagre-d3-es/src/graphlib/index.js";
|
5 | import { u as utils, l as log, x as parseGenericTypes, c as getConfig, i as configureSvgSize } from "./mermaid-6dc72991.js";
|
6 | import "ts-dedent";
|
7 | import "dayjs";
|
8 | import "@braintree/sanitize-url";
|
9 | import "dompurify";
|
10 | import "khroma";
|
11 | import "lodash-es/memoize.js";
|
12 | import "lodash-es/merge.js";
|
13 | import "stylis";
|
14 | import "lodash-es/isEmpty.js";
|
15 | let edgeCount = 0;
|
16 | const drawEdge = function(elem, path, relation, conf, diagObj) {
|
17 | const getRelationType = function(type) {
|
18 | switch (type) {
|
19 | case diagObj.db.relationType.AGGREGATION:
|
20 | return "aggregation";
|
21 | case diagObj.db.relationType.EXTENSION:
|
22 | return "extension";
|
23 | case diagObj.db.relationType.COMPOSITION:
|
24 | return "composition";
|
25 | case diagObj.db.relationType.DEPENDENCY:
|
26 | return "dependency";
|
27 | case diagObj.db.relationType.LOLLIPOP:
|
28 | return "lollipop";
|
29 | }
|
30 | };
|
31 | path.points = path.points.filter((p) => !Number.isNaN(p.y));
|
32 | const lineData = path.points;
|
33 | const lineFunction = line().x(function(d) {
|
34 | return d.x;
|
35 | }).y(function(d) {
|
36 | return d.y;
|
37 | }).curve(curveBasis);
|
38 | const svgPath = elem.append("path").attr("d", lineFunction(lineData)).attr("id", "edge" + edgeCount).attr("class", "relation");
|
39 | let url = "";
|
40 | if (conf.arrowMarkerAbsolute) {
|
41 | url = window.location.protocol + "//" + window.location.host + window.location.pathname + window.location.search;
|
42 | url = url.replace(/\(/g, "\\(");
|
43 | url = url.replace(/\)/g, "\\)");
|
44 | }
|
45 | if (relation.relation.lineType == 1) {
|
46 | svgPath.attr("class", "relation dashed-line");
|
47 | }
|
48 | if (relation.relation.lineType == 10) {
|
49 | svgPath.attr("class", "relation dotted-line");
|
50 | }
|
51 | if (relation.relation.type1 !== "none") {
|
52 | svgPath.attr(
|
53 | "marker-start",
|
54 | "url(" + url + "#" + getRelationType(relation.relation.type1) + "Start)"
|
55 | );
|
56 | }
|
57 | if (relation.relation.type2 !== "none") {
|
58 | svgPath.attr(
|
59 | "marker-end",
|
60 | "url(" + url + "#" + getRelationType(relation.relation.type2) + "End)"
|
61 | );
|
62 | }
|
63 | let x, y;
|
64 | const l = path.points.length;
|
65 | let labelPosition = utils.calcLabelPosition(path.points);
|
66 | x = labelPosition.x;
|
67 | y = labelPosition.y;
|
68 | let p1_card_x, p1_card_y;
|
69 | let p2_card_x, p2_card_y;
|
70 | if (l % 2 !== 0 && l > 1) {
|
71 | let cardinality_1_point = utils.calcCardinalityPosition(
|
72 | relation.relation.type1 !== "none",
|
73 | path.points,
|
74 | path.points[0]
|
75 | );
|
76 | let cardinality_2_point = utils.calcCardinalityPosition(
|
77 | relation.relation.type2 !== "none",
|
78 | path.points,
|
79 | path.points[l - 1]
|
80 | );
|
81 | log.debug("cardinality_1_point " + JSON.stringify(cardinality_1_point));
|
82 | log.debug("cardinality_2_point " + JSON.stringify(cardinality_2_point));
|
83 | p1_card_x = cardinality_1_point.x;
|
84 | p1_card_y = cardinality_1_point.y;
|
85 | p2_card_x = cardinality_2_point.x;
|
86 | p2_card_y = cardinality_2_point.y;
|
87 | }
|
88 | if (relation.title !== void 0) {
|
89 | const g = elem.append("g").attr("class", "classLabel");
|
90 | const label = g.append("text").attr("class", "label").attr("x", x).attr("y", y).attr("fill", "red").attr("text-anchor", "middle").text(relation.title);
|
91 | window.label = label;
|
92 | const bounds = label.node().getBBox();
|
93 | g.insert("rect", ":first-child").attr("class", "box").attr("x", bounds.x - conf.padding / 2).attr("y", bounds.y - conf.padding / 2).attr("width", bounds.width + conf.padding).attr("height", bounds.height + conf.padding);
|
94 | }
|
95 | log.info("Rendering relation " + JSON.stringify(relation));
|
96 | if (relation.relationTitle1 !== void 0 && relation.relationTitle1 !== "none") {
|
97 | const g = elem.append("g").attr("class", "cardinality");
|
98 | g.append("text").attr("class", "type1").attr("x", p1_card_x).attr("y", p1_card_y).attr("fill", "black").attr("font-size", "6").text(relation.relationTitle1);
|
99 | }
|
100 | if (relation.relationTitle2 !== void 0 && relation.relationTitle2 !== "none") {
|
101 | const g = elem.append("g").attr("class", "cardinality");
|
102 | g.append("text").attr("class", "type2").attr("x", p2_card_x).attr("y", p2_card_y).attr("fill", "black").attr("font-size", "6").text(relation.relationTitle2);
|
103 | }
|
104 | edgeCount++;
|
105 | };
|
106 | const drawClass = function(elem, classDef, conf, diagObj) {
|
107 | log.debug("Rendering class ", classDef, conf);
|
108 | const id = classDef.id;
|
109 | const classInfo = {
|
110 | id,
|
111 | label: classDef.id,
|
112 | width: 0,
|
113 | height: 0
|
114 | };
|
115 | const g = elem.append("g").attr("id", diagObj.db.lookUpDomId(id)).attr("class", "classGroup");
|
116 | let title;
|
117 | if (classDef.link) {
|
118 | title = g.append("svg:a").attr("xlink:href", classDef.link).attr("target", classDef.linkTarget).append("text").attr("y", conf.textHeight + conf.padding).attr("x", 0);
|
119 | } else {
|
120 | title = g.append("text").attr("y", conf.textHeight + conf.padding).attr("x", 0);
|
121 | }
|
122 | let isFirst = true;
|
123 | classDef.annotations.forEach(function(member) {
|
124 | const titleText2 = title.append("tspan").text("«" + member + "»");
|
125 | if (!isFirst) {
|
126 | titleText2.attr("dy", conf.textHeight);
|
127 | }
|
128 | isFirst = false;
|
129 | });
|
130 | let classTitleString = getClassTitleString(classDef);
|
131 | const classTitle = title.append("tspan").text(classTitleString).attr("class", "title");
|
132 | if (!isFirst) {
|
133 | classTitle.attr("dy", conf.textHeight);
|
134 | }
|
135 | const titleHeight = title.node().getBBox().height;
|
136 | let membersLine;
|
137 | let membersBox;
|
138 | let methodsLine;
|
139 | if (classDef.members.length > 0) {
|
140 | membersLine = g.append("line").attr("x1", 0).attr("y1", conf.padding + titleHeight + conf.dividerMargin / 2).attr("y2", conf.padding + titleHeight + conf.dividerMargin / 2);
|
141 | const members = g.append("text").attr("x", conf.padding).attr("y", titleHeight + conf.dividerMargin + conf.textHeight).attr("fill", "white").attr("class", "classText");
|
142 | isFirst = true;
|
143 | classDef.members.forEach(function(member) {
|
144 | addTspan(members, member, isFirst, conf);
|
145 | isFirst = false;
|
146 | });
|
147 | membersBox = members.node().getBBox();
|
148 | }
|
149 | if (classDef.methods.length > 0) {
|
150 | methodsLine = g.append("line").attr("x1", 0).attr("y1", conf.padding + titleHeight + conf.dividerMargin + membersBox.height).attr("y2", conf.padding + titleHeight + conf.dividerMargin + membersBox.height);
|
151 | const methods = g.append("text").attr("x", conf.padding).attr("y", titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight).attr("fill", "white").attr("class", "classText");
|
152 | isFirst = true;
|
153 | classDef.methods.forEach(function(method) {
|
154 | addTspan(methods, method, isFirst, conf);
|
155 | isFirst = false;
|
156 | });
|
157 | }
|
158 | const classBox = g.node().getBBox();
|
159 | var cssClassStr = " ";
|
160 | if (classDef.cssClasses.length > 0) {
|
161 | cssClassStr = cssClassStr + classDef.cssClasses.join(" ");
|
162 | }
|
163 | const rect = g.insert("rect", ":first-child").attr("x", 0).attr("y", 0).attr("width", classBox.width + 2 * conf.padding).attr("height", classBox.height + conf.padding + 0.5 * conf.dividerMargin).attr("class", cssClassStr);
|
164 | const rectWidth = rect.node().getBBox().width;
|
165 | title.node().childNodes.forEach(function(x) {
|
166 | x.setAttribute("x", (rectWidth - x.getBBox().width) / 2);
|
167 | });
|
168 | if (classDef.tooltip) {
|
169 | title.insert("title").text(classDef.tooltip);
|
170 | }
|
171 | if (membersLine) {
|
172 | membersLine.attr("x2", rectWidth);
|
173 | }
|
174 | if (methodsLine) {
|
175 | methodsLine.attr("x2", rectWidth);
|
176 | }
|
177 | classInfo.width = rectWidth;
|
178 | classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin;
|
179 | return classInfo;
|
180 | };
|
181 | const getClassTitleString = function(classDef) {
|
182 | let classTitleString = classDef.id;
|
183 | if (classDef.type) {
|
184 | classTitleString += "<" + parseGenericTypes(classDef.type) + ">";
|
185 | }
|
186 | return classTitleString;
|
187 | };
|
188 | const drawNote = function(elem, note, conf, diagObj) {
|
189 | log.debug("Rendering note ", note, conf);
|
190 | const id = note.id;
|
191 | const noteInfo = {
|
192 | id,
|
193 | text: note.text,
|
194 | width: 0,
|
195 | height: 0
|
196 | };
|
197 | const g = elem.append("g").attr("id", id).attr("class", "classGroup");
|
198 | let text = g.append("text").attr("y", conf.textHeight + conf.padding).attr("x", 0);
|
199 | const lines = JSON.parse(`"${note.text}"`).split("\n");
|
200 | lines.forEach(function(line2) {
|
201 | log.debug(`Adding line: ${line2}`);
|
202 | text.append("tspan").text(line2).attr("class", "title").attr("dy", conf.textHeight);
|
203 | });
|
204 | const noteBox = g.node().getBBox();
|
205 | const rect = g.insert("rect", ":first-child").attr("x", 0).attr("y", 0).attr("width", noteBox.width + 2 * conf.padding).attr(
|
206 | "height",
|
207 | noteBox.height + lines.length * conf.textHeight + conf.padding + 0.5 * conf.dividerMargin
|
208 | );
|
209 | const rectWidth = rect.node().getBBox().width;
|
210 | text.node().childNodes.forEach(function(x) {
|
211 | x.setAttribute("x", (rectWidth - x.getBBox().width) / 2);
|
212 | });
|
213 | noteInfo.width = rectWidth;
|
214 | noteInfo.height = noteBox.height + lines.length * conf.textHeight + conf.padding + 0.5 * conf.dividerMargin;
|
215 | return noteInfo;
|
216 | };
|
217 | const addTspan = function(textEl, member, isFirst, conf) {
|
218 | const { displayText, cssStyle } = member.getDisplayDetails();
|
219 | const tSpan = textEl.append("tspan").attr("x", conf.padding).text(displayText);
|
220 | if (cssStyle !== "") {
|
221 | tSpan.attr("style", member.cssStyle);
|
222 | }
|
223 | if (!isFirst) {
|
224 | tSpan.attr("dy", conf.textHeight);
|
225 | }
|
226 | };
|
227 | const svgDraw = {
|
228 | getClassTitleString,
|
229 | drawClass,
|
230 | drawEdge,
|
231 | drawNote
|
232 | };
|
233 | let idCache = {};
|
234 | const padding = 20;
|
235 | const getGraphId = function(label) {
|
236 | const foundEntry = Object.entries(idCache).find((entry) => entry[1].label === label);
|
237 | if (foundEntry) {
|
238 | return foundEntry[0];
|
239 | }
|
240 | };
|
241 | const insertMarkers = function(elem) {
|
242 | elem.append("defs").append("marker").attr("id", "extensionStart").attr("class", "extension").attr("refX", 0).attr("refY", 7).attr("markerWidth", 190).attr("markerHeight", 240).attr("orient", "auto").append("path").attr("d", "M 1,7 L18,13 V 1 Z");
|
243 | elem.append("defs").append("marker").attr("id", "extensionEnd").attr("refX", 19).attr("refY", 7).attr("markerWidth", 20).attr("markerHeight", 28).attr("orient", "auto").append("path").attr("d", "M 1,1 V 13 L18,7 Z");
|
244 | elem.append("defs").append("marker").attr("id", "compositionStart").attr("class", "extension").attr("refX", 0).attr("refY", 7).attr("markerWidth", 190).attr("markerHeight", 240).attr("orient", "auto").append("path").attr("d", "M 18,7 L9,13 L1,7 L9,1 Z");
|
245 | elem.append("defs").append("marker").attr("id", "compositionEnd").attr("refX", 19).attr("refY", 7).attr("markerWidth", 20).attr("markerHeight", 28).attr("orient", "auto").append("path").attr("d", "M 18,7 L9,13 L1,7 L9,1 Z");
|
246 | elem.append("defs").append("marker").attr("id", "aggregationStart").attr("class", "extension").attr("refX", 0).attr("refY", 7).attr("markerWidth", 190).attr("markerHeight", 240).attr("orient", "auto").append("path").attr("d", "M 18,7 L9,13 L1,7 L9,1 Z");
|
247 | elem.append("defs").append("marker").attr("id", "aggregationEnd").attr("refX", 19).attr("refY", 7).attr("markerWidth", 20).attr("markerHeight", 28).attr("orient", "auto").append("path").attr("d", "M 18,7 L9,13 L1,7 L9,1 Z");
|
248 | elem.append("defs").append("marker").attr("id", "dependencyStart").attr("class", "extension").attr("refX", 0).attr("refY", 7).attr("markerWidth", 190).attr("markerHeight", 240).attr("orient", "auto").append("path").attr("d", "M 5,7 L9,13 L1,7 L9,1 Z");
|
249 | elem.append("defs").append("marker").attr("id", "dependencyEnd").attr("refX", 19).attr("refY", 7).attr("markerWidth", 20).attr("markerHeight", 28).attr("orient", "auto").append("path").attr("d", "M 18,7 L9,13 L14,7 L9,1 Z");
|
250 | };
|
251 | const draw = function(text, id, _version, diagObj) {
|
252 | const conf = getConfig().class;
|
253 | idCache = {};
|
254 | log.info("Rendering diagram " + text);
|
255 | const securityLevel = getConfig().securityLevel;
|
256 | let sandboxElement;
|
257 | if (securityLevel === "sandbox") {
|
258 | sandboxElement = select("#i" + id);
|
259 | }
|
260 | const root = securityLevel === "sandbox" ? select(sandboxElement.nodes()[0].contentDocument.body) : select("body");
|
261 | const diagram2 = root.select(`[id='${id}']`);
|
262 | insertMarkers(diagram2);
|
263 | const g = new graphlib.Graph({
|
264 | multigraph: true
|
265 | });
|
266 | g.setGraph({
|
267 | isMultiGraph: true
|
268 | });
|
269 | g.setDefaultEdgeLabel(function() {
|
270 | return {};
|
271 | });
|
272 | const classes = diagObj.db.getClasses();
|
273 | const keys = Object.keys(classes);
|
274 | for (const key of keys) {
|
275 | const classDef = classes[key];
|
276 | const node = svgDraw.drawClass(diagram2, classDef, conf, diagObj);
|
277 | idCache[node.id] = node;
|
278 | g.setNode(node.id, node);
|
279 | log.info("Org height: " + node.height);
|
280 | }
|
281 | const relations = diagObj.db.getRelations();
|
282 | relations.forEach(function(relation) {
|
283 | log.info(
|
284 |
|
285 | "tjoho" + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation)
|
286 | );
|
287 | g.setEdge(
|
288 | getGraphId(relation.id1),
|
289 | getGraphId(relation.id2),
|
290 | {
|
291 | relation
|
292 | },
|
293 | relation.title || "DEFAULT"
|
294 | );
|
295 | });
|
296 | const notes = diagObj.db.getNotes();
|
297 | notes.forEach(function(note) {
|
298 | log.debug(`Adding note: ${JSON.stringify(note)}`);
|
299 | const node = svgDraw.drawNote(diagram2, note, conf, diagObj);
|
300 | idCache[node.id] = node;
|
301 | g.setNode(node.id, node);
|
302 | if (note.class && note.class in classes) {
|
303 | g.setEdge(
|
304 | note.id,
|
305 | getGraphId(note.class),
|
306 | {
|
307 | relation: {
|
308 | id1: note.id,
|
309 | id2: note.class,
|
310 | relation: {
|
311 | type1: "none",
|
312 | type2: "none",
|
313 | lineType: 10
|
314 | }
|
315 | }
|
316 | },
|
317 | "DEFAULT"
|
318 | );
|
319 | }
|
320 | });
|
321 | layout(g);
|
322 | g.nodes().forEach(function(v) {
|
323 | if (v !== void 0 && g.node(v) !== void 0) {
|
324 | log.debug("Node " + v + ": " + JSON.stringify(g.node(v)));
|
325 | root.select("#" + (diagObj.db.lookUpDomId(v) || v)).attr(
|
326 | "transform",
|
327 | "translate(" + (g.node(v).x - g.node(v).width / 2) + "," + (g.node(v).y - g.node(v).height / 2) + " )"
|
328 | );
|
329 | }
|
330 | });
|
331 | g.edges().forEach(function(e) {
|
332 | if (e !== void 0 && g.edge(e) !== void 0) {
|
333 | log.debug("Edge " + e.v + " -> " + e.w + ": " + JSON.stringify(g.edge(e)));
|
334 | svgDraw.drawEdge(diagram2, g.edge(e), g.edge(e).relation, conf, diagObj);
|
335 | }
|
336 | });
|
337 | const svgBounds = diagram2.node().getBBox();
|
338 | const width = svgBounds.width + padding * 2;
|
339 | const height = svgBounds.height + padding * 2;
|
340 | configureSvgSize(diagram2, height, width, conf.useMaxWidth);
|
341 | const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
|
342 | log.debug(`viewBox ${vBox}`);
|
343 | diagram2.attr("viewBox", vBox);
|
344 | };
|
345 | const renderer = {
|
346 | draw
|
347 | };
|
348 | const diagram = {
|
349 | parser,
|
350 | db,
|
351 | renderer,
|
352 | styles,
|
353 | init: (cnf) => {
|
354 | if (!cnf.class) {
|
355 | cnf.class = {};
|
356 | }
|
357 | cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
358 | db.clear();
|
359 | }
|
360 | };
|
361 | export {
|
362 | diagram
|
363 | };
|