UNPKG

14.9 kBJavaScriptView Raw
1import { p as parser, d as db, s as styles } from "./styles-b83b31c9.js";
2import { line, curveBasis, select } from "d3";
3import { layout } from "dagre-d3-es/src/dagre/index.js";
4import * as graphlib from "dagre-d3-es/src/graphlib/index.js";
5import { u as utils, l as log, x as parseGenericTypes, c as getConfig, i as configureSvgSize } from "./mermaid-6dc72991.js";
6import "ts-dedent";
7import "dayjs";
8import "@braintree/sanitize-url";
9import "dompurify";
10import "khroma";
11import "lodash-es/memoize.js";
12import "lodash-es/merge.js";
13import "stylis";
14import "lodash-es/isEmpty.js";
15let edgeCount = 0;
16const 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};
106const 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};
181const getClassTitleString = function(classDef) {
182 let classTitleString = classDef.id;
183 if (classDef.type) {
184 classTitleString += "<" + parseGenericTypes(classDef.type) + ">";
185 }
186 return classTitleString;
187};
188const 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};
217const 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};
227const svgDraw = {
228 getClassTitleString,
229 drawClass,
230 drawEdge,
231 drawNote
232};
233let idCache = {};
234const padding = 20;
235const getGraphId = function(label) {
236 const foundEntry = Object.entries(idCache).find((entry) => entry[1].label === label);
237 if (foundEntry) {
238 return foundEntry[0];
239 }
240};
241const 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};
251const 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 // cspell:ignore tjoho
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};
345const renderer = {
346 draw
347};
348const 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};
361export {
362 diagram
363};