kumiki 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +256 -0
- data/lib/kumiki/animation/animated_state.rb +83 -0
- data/lib/kumiki/animation/easing.rb +62 -0
- data/lib/kumiki/animation/value_tween.rb +69 -0
- data/lib/kumiki/app.rb +381 -0
- data/lib/kumiki/box.rb +40 -0
- data/lib/kumiki/chart/area_chart.rb +308 -0
- data/lib/kumiki/chart/bar_chart.rb +291 -0
- data/lib/kumiki/chart/base_chart.rb +213 -0
- data/lib/kumiki/chart/chart_helpers.rb +74 -0
- data/lib/kumiki/chart/gauge_chart.rb +174 -0
- data/lib/kumiki/chart/heatmap_chart.rb +223 -0
- data/lib/kumiki/chart/line_chart.rb +292 -0
- data/lib/kumiki/chart/pie_chart.rb +222 -0
- data/lib/kumiki/chart/scales.rb +79 -0
- data/lib/kumiki/chart/scatter_chart.rb +306 -0
- data/lib/kumiki/chart/stacked_bar_chart.rb +279 -0
- data/lib/kumiki/column.rb +351 -0
- data/lib/kumiki/core.rb +2511 -0
- data/lib/kumiki/dsl.rb +408 -0
- data/lib/kumiki/frame_ranma.rb +570 -0
- data/lib/kumiki/markdown/ast.rb +127 -0
- data/lib/kumiki/markdown/mermaid/layout.rb +389 -0
- data/lib/kumiki/markdown/mermaid/models.rb +235 -0
- data/lib/kumiki/markdown/mermaid/parser.rb +522 -0
- data/lib/kumiki/markdown/mermaid/renderer.rb +339 -0
- data/lib/kumiki/markdown/parser.rb +808 -0
- data/lib/kumiki/markdown/renderer.rb +642 -0
- data/lib/kumiki/markdown/theme.rb +168 -0
- data/lib/kumiki/render_node.rb +262 -0
- data/lib/kumiki/row.rb +288 -0
- data/lib/kumiki/spacer.rb +20 -0
- data/lib/kumiki/style.rb +799 -0
- data/lib/kumiki/theme.rb +567 -0
- data/lib/kumiki/themes/material.rb +40 -0
- data/lib/kumiki/themes/tokyo_night.rb +11 -0
- data/lib/kumiki/version.rb +5 -0
- data/lib/kumiki/widgets/button.rb +105 -0
- data/lib/kumiki/widgets/calendar.rb +1028 -0
- data/lib/kumiki/widgets/checkbox.rb +119 -0
- data/lib/kumiki/widgets/container.rb +111 -0
- data/lib/kumiki/widgets/data_table.rb +670 -0
- data/lib/kumiki/widgets/divider.rb +31 -0
- data/lib/kumiki/widgets/image.rb +105 -0
- data/lib/kumiki/widgets/input.rb +485 -0
- data/lib/kumiki/widgets/markdown.rb +58 -0
- data/lib/kumiki/widgets/modal.rb +165 -0
- data/lib/kumiki/widgets/multiline_input.rb +970 -0
- data/lib/kumiki/widgets/multiline_text.rb +180 -0
- data/lib/kumiki/widgets/net_image.rb +100 -0
- data/lib/kumiki/widgets/progress_bar.rb +72 -0
- data/lib/kumiki/widgets/radio_buttons.rb +93 -0
- data/lib/kumiki/widgets/slider.rb +135 -0
- data/lib/kumiki/widgets/switch.rb +84 -0
- data/lib/kumiki/widgets/tabs.rb +175 -0
- data/lib/kumiki/widgets/text.rb +120 -0
- data/lib/kumiki/widgets/tree.rb +434 -0
- data/lib/kumiki/widgets/webview.rb +87 -0
- data/lib/kumiki.rb +130 -0
- metadata +113 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
module Kumiki
|
|
2
|
+
# Mermaid flowchart layout - BFS layered graph layout
|
|
3
|
+
# Assigns x, y, width, height to all nodes and subgraphs
|
|
4
|
+
|
|
5
|
+
class MermaidLayout
|
|
6
|
+
def layout(diagram, max_width, padding)
|
|
7
|
+
if diagram.nodes.length == 0
|
|
8
|
+
return
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
assign_layers(diagram)
|
|
12
|
+
calculate_node_sizes(diagram)
|
|
13
|
+
|
|
14
|
+
horizontal = diagram.direction == MERMAID_DIR_LR || diagram.direction == MERMAID_DIR_RL
|
|
15
|
+
if horizontal
|
|
16
|
+
position_horizontal(diagram, padding)
|
|
17
|
+
else
|
|
18
|
+
position_vertical(diagram, padding, max_width)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
position_subgraphs(diagram)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def assign_layers(diagram)
|
|
25
|
+
# Simple BFS layering using node.layer field
|
|
26
|
+
# First, set all layers to -1 (unvisited)
|
|
27
|
+
i = 0
|
|
28
|
+
while i < diagram.nodes.length
|
|
29
|
+
diagram.nodes[i].layer = -1
|
|
30
|
+
i = i + 1
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Find root nodes (not a target of any edge)
|
|
34
|
+
i = 0
|
|
35
|
+
while i < diagram.nodes.length
|
|
36
|
+
n = diagram.nodes[i]
|
|
37
|
+
is_root = true
|
|
38
|
+
ei = 0
|
|
39
|
+
while ei < diagram.edges.length
|
|
40
|
+
if diagram.edges[ei].target == n.id
|
|
41
|
+
is_root = false
|
|
42
|
+
break
|
|
43
|
+
end
|
|
44
|
+
ei = ei + 1
|
|
45
|
+
end
|
|
46
|
+
if is_root
|
|
47
|
+
n.layer = 0
|
|
48
|
+
end
|
|
49
|
+
i = i + 1
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# If no roots, set first node as root
|
|
53
|
+
has_root = false
|
|
54
|
+
i = 0
|
|
55
|
+
while i < diagram.nodes.length
|
|
56
|
+
if diagram.nodes[i].layer == 0
|
|
57
|
+
has_root = true
|
|
58
|
+
break
|
|
59
|
+
end
|
|
60
|
+
i = i + 1
|
|
61
|
+
end
|
|
62
|
+
if !has_root && diagram.nodes.length > 0
|
|
63
|
+
diagram.nodes[0].layer = 0
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# BFS: propagate layers from roots to children
|
|
67
|
+
# Only assign to unvisited nodes (layer < 0) to handle cycles gracefully
|
|
68
|
+
changed = true
|
|
69
|
+
max_iters = diagram.nodes.length
|
|
70
|
+
iter = 0
|
|
71
|
+
while changed && iter < max_iters
|
|
72
|
+
changed = false
|
|
73
|
+
ei = 0
|
|
74
|
+
while ei < diagram.edges.length
|
|
75
|
+
edge = diagram.edges[ei]
|
|
76
|
+
src = diagram.get_node(edge.source)
|
|
77
|
+
tgt = diagram.get_node(edge.target)
|
|
78
|
+
if src && tgt && src.layer >= 0 && tgt.layer < 0
|
|
79
|
+
tgt.layer = src.layer + 1
|
|
80
|
+
changed = true
|
|
81
|
+
end
|
|
82
|
+
ei = ei + 1
|
|
83
|
+
end
|
|
84
|
+
iter = iter + 1
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Set any remaining unvisited nodes to layer 0
|
|
88
|
+
i = 0
|
|
89
|
+
while i < diagram.nodes.length
|
|
90
|
+
if diagram.nodes[i].layer < 0
|
|
91
|
+
diagram.nodes[i].layer = 0
|
|
92
|
+
end
|
|
93
|
+
i = i + 1
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def calculate_node_sizes(diagram)
|
|
98
|
+
char_width = 8.0
|
|
99
|
+
min_width = 100.0
|
|
100
|
+
node_height = 40.0
|
|
101
|
+
|
|
102
|
+
i = 0
|
|
103
|
+
while i < diagram.nodes.length
|
|
104
|
+
n = diagram.nodes[i]
|
|
105
|
+
label_w = n.label.length * char_width + 24.0
|
|
106
|
+
if label_w < min_width
|
|
107
|
+
label_w = min_width
|
|
108
|
+
end
|
|
109
|
+
n.width = label_w
|
|
110
|
+
n.height = node_height
|
|
111
|
+
|
|
112
|
+
if n.shape == MERMAID_SHAPE_CIRCLE
|
|
113
|
+
max_dim = n.width
|
|
114
|
+
if n.height > max_dim
|
|
115
|
+
max_dim = n.height
|
|
116
|
+
end
|
|
117
|
+
n.width = max_dim
|
|
118
|
+
n.height = max_dim
|
|
119
|
+
elsif n.shape == MERMAID_SHAPE_DIAMOND
|
|
120
|
+
n.width = n.width + 20.0
|
|
121
|
+
n.height = n.width * 0.6
|
|
122
|
+
end
|
|
123
|
+
i = i + 1
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def max_layer(diagram)
|
|
128
|
+
mx = 0
|
|
129
|
+
i = 0
|
|
130
|
+
while i < diagram.nodes.length
|
|
131
|
+
if diagram.nodes[i].layer > mx
|
|
132
|
+
mx = diagram.nodes[i].layer
|
|
133
|
+
end
|
|
134
|
+
i = i + 1
|
|
135
|
+
end
|
|
136
|
+
mx
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def position_vertical(diagram, padding, max_width)
|
|
140
|
+
h_spacing = 40.0
|
|
141
|
+
v_spacing = 60.0
|
|
142
|
+
ml = max_layer(diagram)
|
|
143
|
+
reverse = diagram.direction == MERMAID_DIR_BT
|
|
144
|
+
|
|
145
|
+
# First pass: find max total width across all layers
|
|
146
|
+
max_w = find_max_layer_width(diagram, ml, h_spacing)
|
|
147
|
+
if max_w < 1.0
|
|
148
|
+
max_w = max_width
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Second pass: position nodes
|
|
152
|
+
y_offset = padding
|
|
153
|
+
layer = 0
|
|
154
|
+
while layer <= ml
|
|
155
|
+
actual = layer
|
|
156
|
+
if reverse
|
|
157
|
+
actual = ml - layer
|
|
158
|
+
end
|
|
159
|
+
position_layer_vertical(diagram, actual, y_offset, padding, max_w, h_spacing)
|
|
160
|
+
tallest = layer_max_height(diagram, actual)
|
|
161
|
+
y_offset = y_offset + tallest + v_spacing
|
|
162
|
+
layer = layer + 1
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def find_max_layer_width(diagram, ml, spacing)
|
|
167
|
+
max_w = 0.0
|
|
168
|
+
layer = 0
|
|
169
|
+
while layer <= ml
|
|
170
|
+
w = compute_layer_width(diagram, layer, spacing)
|
|
171
|
+
if w > max_w
|
|
172
|
+
max_w = w
|
|
173
|
+
end
|
|
174
|
+
layer = layer + 1
|
|
175
|
+
end
|
|
176
|
+
max_w
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def compute_layer_width(diagram, layer, spacing)
|
|
180
|
+
total = 0.0
|
|
181
|
+
count = 0
|
|
182
|
+
i = 0
|
|
183
|
+
while i < diagram.nodes.length
|
|
184
|
+
if diagram.nodes[i].layer == layer
|
|
185
|
+
total = total + diagram.nodes[i].width
|
|
186
|
+
count = count + 1
|
|
187
|
+
end
|
|
188
|
+
i = i + 1
|
|
189
|
+
end
|
|
190
|
+
if count > 1
|
|
191
|
+
total = total + (count - 1) * spacing
|
|
192
|
+
end
|
|
193
|
+
total
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def position_layer_vertical(diagram, layer, y, padding, max_w, spacing)
|
|
197
|
+
lw = compute_layer_width(diagram, layer, spacing)
|
|
198
|
+
start_x = padding + (max_w - lw) / 2.0
|
|
199
|
+
x = start_x
|
|
200
|
+
i = 0
|
|
201
|
+
while i < diagram.nodes.length
|
|
202
|
+
n = diagram.nodes[i]
|
|
203
|
+
if n.layer == layer
|
|
204
|
+
n.x = x
|
|
205
|
+
n.y = y
|
|
206
|
+
x = x + n.width + spacing
|
|
207
|
+
end
|
|
208
|
+
i = i + 1
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def layer_max_height(diagram, layer)
|
|
213
|
+
mx = 0.0
|
|
214
|
+
i = 0
|
|
215
|
+
while i < diagram.nodes.length
|
|
216
|
+
if diagram.nodes[i].layer == layer && diagram.nodes[i].height > mx
|
|
217
|
+
mx = diagram.nodes[i].height
|
|
218
|
+
end
|
|
219
|
+
i = i + 1
|
|
220
|
+
end
|
|
221
|
+
mx
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def position_horizontal(diagram, padding)
|
|
225
|
+
h_spacing = 40.0
|
|
226
|
+
v_spacing = 60.0
|
|
227
|
+
ml = max_layer(diagram)
|
|
228
|
+
reverse = diagram.direction == MERMAID_DIR_RL
|
|
229
|
+
|
|
230
|
+
# Find max total height across all layers
|
|
231
|
+
max_h = find_max_layer_height(diagram, ml, h_spacing)
|
|
232
|
+
|
|
233
|
+
# Position nodes
|
|
234
|
+
x_offset = padding
|
|
235
|
+
layer = 0
|
|
236
|
+
while layer <= ml
|
|
237
|
+
actual = layer
|
|
238
|
+
if reverse
|
|
239
|
+
actual = ml - layer
|
|
240
|
+
end
|
|
241
|
+
position_layer_horizontal(diagram, actual, x_offset, padding, max_h, h_spacing)
|
|
242
|
+
widest = layer_max_width(diagram, actual)
|
|
243
|
+
x_offset = x_offset + widest + v_spacing
|
|
244
|
+
layer = layer + 1
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def find_max_layer_height(diagram, ml, spacing)
|
|
249
|
+
max_h = 0.0
|
|
250
|
+
layer = 0
|
|
251
|
+
while layer <= ml
|
|
252
|
+
h = compute_layer_height(diagram, layer, spacing)
|
|
253
|
+
if h > max_h
|
|
254
|
+
max_h = h
|
|
255
|
+
end
|
|
256
|
+
layer = layer + 1
|
|
257
|
+
end
|
|
258
|
+
max_h
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def compute_layer_height(diagram, layer, spacing)
|
|
262
|
+
total = 0.0
|
|
263
|
+
count = 0
|
|
264
|
+
i = 0
|
|
265
|
+
while i < diagram.nodes.length
|
|
266
|
+
if diagram.nodes[i].layer == layer
|
|
267
|
+
total = total + diagram.nodes[i].height
|
|
268
|
+
count = count + 1
|
|
269
|
+
end
|
|
270
|
+
i = i + 1
|
|
271
|
+
end
|
|
272
|
+
if count > 1
|
|
273
|
+
total = total + (count - 1) * spacing
|
|
274
|
+
end
|
|
275
|
+
total
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def position_layer_horizontal(diagram, layer, x, padding, max_h, spacing)
|
|
279
|
+
lh = compute_layer_height(diagram, layer, spacing)
|
|
280
|
+
start_y = padding + (max_h - lh) / 2.0
|
|
281
|
+
y = start_y
|
|
282
|
+
i = 0
|
|
283
|
+
while i < diagram.nodes.length
|
|
284
|
+
n = diagram.nodes[i]
|
|
285
|
+
if n.layer == layer
|
|
286
|
+
n.x = x
|
|
287
|
+
n.y = y
|
|
288
|
+
y = y + n.height + spacing
|
|
289
|
+
end
|
|
290
|
+
i = i + 1
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def layer_max_width(diagram, layer)
|
|
295
|
+
mx = 0.0
|
|
296
|
+
i = 0
|
|
297
|
+
while i < diagram.nodes.length
|
|
298
|
+
if diagram.nodes[i].layer == layer && diagram.nodes[i].width > mx
|
|
299
|
+
mx = diagram.nodes[i].width
|
|
300
|
+
end
|
|
301
|
+
i = i + 1
|
|
302
|
+
end
|
|
303
|
+
mx
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def position_subgraphs(diagram)
|
|
307
|
+
sg_padding = 15.0
|
|
308
|
+
title_height = 20.0
|
|
309
|
+
|
|
310
|
+
si = 0
|
|
311
|
+
while si < diagram.subgraphs.length
|
|
312
|
+
sg = diagram.subgraphs[si]
|
|
313
|
+
if sg.node_ids.length > 0
|
|
314
|
+
compute_subgraph_bounds(diagram, sg, sg_padding, title_height)
|
|
315
|
+
end
|
|
316
|
+
si = si + 1
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def compute_subgraph_bounds(diagram, sg, sg_padding, title_height)
|
|
321
|
+
min_x = 99999.0
|
|
322
|
+
min_y = 99999.0
|
|
323
|
+
max_x = 0.0
|
|
324
|
+
max_y = 0.0
|
|
325
|
+
|
|
326
|
+
ni = 0
|
|
327
|
+
while ni < sg.node_ids.length
|
|
328
|
+
node = diagram.get_node(sg.node_ids[ni])
|
|
329
|
+
if node
|
|
330
|
+
if node.x < min_x
|
|
331
|
+
min_x = node.x
|
|
332
|
+
end
|
|
333
|
+
if node.y < min_y
|
|
334
|
+
min_y = node.y
|
|
335
|
+
end
|
|
336
|
+
right = node.x + node.width
|
|
337
|
+
if right > max_x
|
|
338
|
+
max_x = right
|
|
339
|
+
end
|
|
340
|
+
bottom = node.y + node.height
|
|
341
|
+
if bottom > max_y
|
|
342
|
+
max_y = bottom
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
ni = ni + 1
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
sg.x = min_x - sg_padding
|
|
349
|
+
sg.y = min_y - sg_padding - title_height
|
|
350
|
+
sg.width = (max_x - min_x) + sg_padding * 2.0
|
|
351
|
+
sg.height = (max_y - min_y) + sg_padding * 2.0 + title_height
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def calculate_height(diagram)
|
|
355
|
+
max_y = 0.0
|
|
356
|
+
i = 0
|
|
357
|
+
while i < diagram.nodes.length
|
|
358
|
+
bottom = diagram.nodes[i].y + diagram.nodes[i].height
|
|
359
|
+
if bottom > max_y
|
|
360
|
+
max_y = bottom
|
|
361
|
+
end
|
|
362
|
+
i = i + 1
|
|
363
|
+
end
|
|
364
|
+
i = 0
|
|
365
|
+
while i < diagram.subgraphs.length
|
|
366
|
+
bottom = diagram.subgraphs[i].y + diagram.subgraphs[i].height
|
|
367
|
+
if bottom > max_y
|
|
368
|
+
max_y = bottom
|
|
369
|
+
end
|
|
370
|
+
i = i + 1
|
|
371
|
+
end
|
|
372
|
+
max_y + 20.0
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def calculate_width(diagram)
|
|
376
|
+
max_x = 0.0
|
|
377
|
+
i = 0
|
|
378
|
+
while i < diagram.nodes.length
|
|
379
|
+
right = diagram.nodes[i].x + diagram.nodes[i].width
|
|
380
|
+
if right > max_x
|
|
381
|
+
max_x = right
|
|
382
|
+
end
|
|
383
|
+
i = i + 1
|
|
384
|
+
end
|
|
385
|
+
max_x + 20.0
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
end
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
module Kumiki
|
|
2
|
+
# Mermaid diagram data models
|
|
3
|
+
# Direction, shape, line type, arrow type constants and node/edge/subgraph classes
|
|
4
|
+
|
|
5
|
+
# Direction constants
|
|
6
|
+
MERMAID_DIR_TB = 0
|
|
7
|
+
MERMAID_DIR_BT = 1
|
|
8
|
+
MERMAID_DIR_LR = 2
|
|
9
|
+
MERMAID_DIR_RL = 3
|
|
10
|
+
|
|
11
|
+
# Node shape constants
|
|
12
|
+
MERMAID_SHAPE_RECT = 0
|
|
13
|
+
MERMAID_SHAPE_ROUNDED = 1
|
|
14
|
+
MERMAID_SHAPE_STADIUM = 2
|
|
15
|
+
MERMAID_SHAPE_CIRCLE = 3
|
|
16
|
+
MERMAID_SHAPE_DIAMOND = 4
|
|
17
|
+
MERMAID_SHAPE_HEXAGON = 5
|
|
18
|
+
MERMAID_SHAPE_SUBROUTINE = 6
|
|
19
|
+
|
|
20
|
+
# Line type constants
|
|
21
|
+
MERMAID_LINE_SOLID = 0
|
|
22
|
+
MERMAID_LINE_DASHED = 1
|
|
23
|
+
MERMAID_LINE_THICK = 2
|
|
24
|
+
|
|
25
|
+
# Arrow type constants
|
|
26
|
+
MERMAID_ARROW_ARROW = 0
|
|
27
|
+
MERMAID_ARROW_OPEN = 1
|
|
28
|
+
MERMAID_ARROW_CIRCLE = 2
|
|
29
|
+
MERMAID_ARROW_CROSS = 3
|
|
30
|
+
|
|
31
|
+
class MermaidNode
|
|
32
|
+
def initialize(id, label, shape)
|
|
33
|
+
@id = id
|
|
34
|
+
@label = label
|
|
35
|
+
@shape = shape
|
|
36
|
+
@x = 0.0
|
|
37
|
+
@y = 0.0
|
|
38
|
+
@width = 0.0
|
|
39
|
+
@height = 0.0
|
|
40
|
+
@layer = 0
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def id
|
|
44
|
+
@id
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def label
|
|
48
|
+
@label
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def label=(v)
|
|
52
|
+
@label = v
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def shape
|
|
56
|
+
@shape
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def shape=(v)
|
|
60
|
+
@shape = v
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def x
|
|
64
|
+
@x
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def x=(v)
|
|
68
|
+
@x = v
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def y
|
|
72
|
+
@y
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def y=(v)
|
|
76
|
+
@y = v
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def width
|
|
80
|
+
@width
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def width=(v)
|
|
84
|
+
@width = v
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def height
|
|
88
|
+
@height
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def height=(v)
|
|
92
|
+
@height = v
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def layer
|
|
96
|
+
@layer
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def layer=(v)
|
|
100
|
+
@layer = v
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
class MermaidEdge
|
|
105
|
+
def initialize(source, target, label, line_type, arrow_type)
|
|
106
|
+
@source = source
|
|
107
|
+
@target = target
|
|
108
|
+
@label = label
|
|
109
|
+
@line_type = line_type
|
|
110
|
+
@arrow_type = arrow_type
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def source
|
|
114
|
+
@source
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def target
|
|
118
|
+
@target
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def label
|
|
122
|
+
@label
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def line_type
|
|
126
|
+
@line_type
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def arrow_type
|
|
130
|
+
@arrow_type
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
class MermaidSubgraph
|
|
135
|
+
def initialize(id, title)
|
|
136
|
+
@id = id
|
|
137
|
+
@title = title
|
|
138
|
+
@node_ids = []
|
|
139
|
+
@x = 0.0
|
|
140
|
+
@y = 0.0
|
|
141
|
+
@width = 0.0
|
|
142
|
+
@height = 0.0
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def id
|
|
146
|
+
@id
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def title
|
|
150
|
+
@title
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def node_ids
|
|
154
|
+
@node_ids
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def x
|
|
158
|
+
@x
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def x=(v)
|
|
162
|
+
@x = v
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def y
|
|
166
|
+
@y
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def y=(v)
|
|
170
|
+
@y = v
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def width
|
|
174
|
+
@width
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def width=(v)
|
|
178
|
+
@width = v
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def height
|
|
182
|
+
@height
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def height=(v)
|
|
186
|
+
@height = v
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
class MermaidDiagram
|
|
191
|
+
def initialize(direction)
|
|
192
|
+
@direction = direction
|
|
193
|
+
@nodes = []
|
|
194
|
+
@edges = []
|
|
195
|
+
@subgraphs = []
|
|
196
|
+
@node_map = {}
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def direction
|
|
200
|
+
@direction
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def nodes
|
|
204
|
+
@nodes
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def edges
|
|
208
|
+
@edges
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def subgraphs
|
|
212
|
+
@subgraphs
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def add_node(node)
|
|
216
|
+
if !@node_map[node.id]
|
|
217
|
+
@nodes.push(node)
|
|
218
|
+
@node_map[node.id] = node
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def get_node(id)
|
|
223
|
+
@node_map[id]
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def add_edge(edge)
|
|
227
|
+
@edges.push(edge)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def add_subgraph(sg)
|
|
231
|
+
@subgraphs.push(sg)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
end
|