drawio_dsl 0.2.0 → 0.4.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.builders/.data/shapes.json +82 -0
  3. data/.builders/.templates/basic/schema_require.rb +16 -0
  4. data/.builders/.templates/schema_shape.rb +9 -0
  5. data/.builders/.templates/schema_shape_spec.rb +13 -0
  6. data/.builders/blueprint/shapes.rb +29 -0
  7. data/.builders/boot.rb +5 -0
  8. data/.builders/generators/90-requires.rb +35 -0
  9. data/.builders/generators/sample_diagrams/10-page-margin.rb +46 -0
  10. data/.builders/generators/sample_diagrams/15-grid-direction.rb +40 -0
  11. data/.builders/generators/sample_diagrams/16-grid-alignment.rb +73 -0
  12. data/.builders/generators/sample_diagrams/20-styles.rb +64 -0
  13. data/.builders/generators/sample_diagrams/25-themes.rb +24 -0
  14. data/.rubocop.yml +2 -1
  15. data/CHANGELOG.md +21 -0
  16. data/lib/drawio_dsl/configuration.rb +56 -43
  17. data/lib/drawio_dsl/dom_builder.rb +25 -0
  18. data/lib/drawio_dsl/drawio.rb +49 -0
  19. data/lib/drawio_dsl/layout_engine.rb +12 -28
  20. data/lib/drawio_dsl/schema/_.rb +23 -0
  21. data/lib/drawio_dsl/schema/common_style.rb +42 -0
  22. data/lib/drawio_dsl/schema/default_palette.rb +31 -0
  23. data/lib/drawio_dsl/schema/diagram.rb +57 -0
  24. data/lib/drawio_dsl/schema/layouts/flex_layout.rb +87 -0
  25. data/lib/drawio_dsl/schema/layouts/grid_layout.rb +102 -0
  26. data/lib/drawio_dsl/schema/layouts/layout.rb +41 -0
  27. data/lib/drawio_dsl/schema/node.rb +53 -0
  28. data/lib/drawio_dsl/schema/page.rb +135 -0
  29. data/lib/drawio_dsl/schema/shapes/callout.rb +9 -0
  30. data/lib/drawio_dsl/schema/shapes/circle.rb +9 -0
  31. data/lib/drawio_dsl/schema/shapes/cloud.rb +9 -0
  32. data/lib/drawio_dsl/schema/shapes/diamond.rb +9 -0
  33. data/lib/drawio_dsl/schema/shapes/ellipse.rb +9 -0
  34. data/lib/drawio_dsl/schema/shapes/hexagon.rb +9 -0
  35. data/lib/drawio_dsl/schema/shapes/note.rb +9 -0
  36. data/lib/drawio_dsl/schema/shapes/process.rb +9 -0
  37. data/lib/drawio_dsl/schema/shapes/rectangle.rb +9 -0
  38. data/lib/drawio_dsl/schema/shapes/shape.rb +125 -0
  39. data/lib/drawio_dsl/schema/shapes/square.rb +9 -0
  40. data/lib/drawio_dsl/version.rb +1 -1
  41. data/lib/drawio_dsl.rb +1 -1
  42. data/package-lock.json +2 -2
  43. data/package.json +1 -1
  44. metadata +33 -5
  45. data/.builders/generators/10-layout.rb +0 -34
  46. data/lib/drawio_dsl/drawio_dsl-OLD.x +0 -335
  47. data/lib/drawio_dsl/schema.rb +0 -604
@@ -1,604 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DrawioDsl
4
- module Schema
5
- # Common Style is the reused on Diagram, Page and Shape
6
- #
7
- # When styles are not provided at each level, then they will inherit from
8
- # the parent common style.
9
- #
10
- # Shapes will use the common style of their page
11
- class CommonStyle
12
- attr_accessor :theme
13
- attr_accessor :white_space
14
- attr_accessor :html
15
- attr_accessor :rounded
16
- attr_accessor :shadow
17
- attr_accessor :glass
18
- attr_accessor :sketch
19
-
20
- def initialize(**args, &block)
21
- @white_space = args[:white_space]
22
- @html = args[:html]
23
- @rounded = args[:rounded]
24
- @shadow = args[:shadow]
25
- @sketch = args[:sketch]
26
- @glass = args[:glass]
27
-
28
- instance_eval(&block) if block_given?
29
- end
30
-
31
- def to_h
32
- {
33
- white_space: white_space,
34
- html: html,
35
- rounded: rounded,
36
- shadow: shadow,
37
- sketch: sketch,
38
- glass: glass
39
- }
40
- end
41
- end
42
-
43
- # Default Palette contains palette information that can be inherited at each level
44
- class DefaultPalette
45
- attr_accessor :fill_color
46
- attr_accessor :stroke_color
47
- attr_accessor :font_color
48
- attr_accessor :gradient
49
-
50
- def initialize(owner, **args, &block)
51
- @fill_color = args[:fill_color]
52
- @stroke_color = args[:stroke_color]
53
- @font_color = args[:font_color]
54
- @gradient = args[:gradient]
55
-
56
- instance_exec(owner, &block) if block_given?
57
- end
58
-
59
- def to_h
60
- {
61
- fill_color: fill_color,
62
- stroke_color: stroke_color,
63
- font_color: font_color,
64
- gradient: gradient
65
- }
66
- end
67
- end
68
-
69
- # Diagram is the root of the schema, it contains pages
70
- class Diagram
71
- attr_accessor :host
72
- attr_accessor :theme
73
- attr_accessor :style
74
- attr_accessor :palette
75
- attr_accessor :pages
76
-
77
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
78
- def initialize(**args)
79
- @host = args[:host] || SecureRandom.alphanumeric(3)
80
-
81
- # Apply a random theme to the diagram if none is specified.
82
- @theme = args[:theme] || KConfig.configuration.drawio.random_theme
83
-
84
- @style = DrawioDsl::Schema::CommonStyle.new(**args) do
85
- default_style = KConfig.configuration.drawio.base_style
86
-
87
- # Inherit from configured style when specific style not specified.
88
- @white_space ||= default_style.white_space
89
- @html ||= default_style.html
90
- @rounded ||= default_style.rounded
91
- @shadow ||= default_style.shadow
92
- @sketch ||= default_style.sketch
93
- @glass ||= default_style.glass
94
- end
95
-
96
- @palette = DrawioDsl::Schema::DefaultPalette.new(self, **args) do |diagram|
97
- theme_palette = KConfig.configuration.drawio.palette(diagram.theme)
98
-
99
- # Inherit from theme when specific palette options are not specified.
100
- @fill_color ||= theme_palette.fill_color
101
- @stroke_color ||= theme_palette.stroke_color
102
- @font_color ||= theme_palette.font_color
103
- @gradient ||= theme_palette.gradient
104
- end
105
-
106
- @pages = args[:pages] || []
107
- end
108
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
109
-
110
- def to_h
111
- {
112
- host: host,
113
- theme: theme,
114
- palette: palette.to_h,
115
- style: style.to_h,
116
- pages: pages.map(&:to_h)
117
- }
118
- end
119
- end
120
-
121
- # Page is a container for nodes
122
- class Page
123
- attr_accessor :diagram
124
-
125
- # These transient attributes hold the current x, y location for the last element added to the page
126
- attr_accessor :position_x
127
- attr_accessor :position_y
128
-
129
- attr_accessor :id
130
- attr_accessor :name
131
- attr_accessor :theme
132
- attr_accessor :style
133
- attr_accessor :palette
134
- attr_accessor :margin_left
135
- attr_accessor :margin_top
136
- attr_accessor :nodes
137
-
138
- # attr_accessor :dx # dx = "2636"
139
- # attr_accessor :dy # dy = "2332"
140
- attr_accessor :grid # grid = "0"
141
- attr_accessor :grid_size # gridSize = "10"
142
- attr_accessor :guides # guides = "1"
143
- attr_accessor :tooltips # tooltips = "1"
144
- attr_accessor :connect # connect = "1"
145
- attr_accessor :arrows # arrows = "1"
146
- attr_accessor :fold # fold = "1"
147
- attr_accessor :page_no # page = "1"
148
- attr_accessor :page_scale # pageScale = "1"
149
- attr_accessor :page_width # pageWidth = "583"
150
- attr_accessor :page_height # pageHeight = "827"
151
- attr_accessor :background # background = "#FFFACD"
152
- attr_accessor :page_shadow # shadow = "0"
153
- attr_accessor :math # math = "0"
154
-
155
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
156
- def initialize(diagram, **args)
157
- @diagram = diagram
158
-
159
- @position_x = 0
160
- @position_y = 0
161
-
162
- @id = args[:id]
163
- @name = args[:name]
164
- @theme = args[:theme] || diagram.theme
165
- @margin_left = args[:margin_left] || 50
166
- @margin_top = args[:margin_top] || 50
167
-
168
- @grid = args[:grid] || 0
169
- @grid_size = args[:grid_size] || 10
170
- @guides = args[:guides] || 1
171
- @tooltips = args[:tooltips] || 1
172
- @connect = args[:connect] || 1
173
- @arrows = args[:arrows] || 1
174
- @fold = args[:fold] || 1
175
- @page_no = args[:page_no] || 1
176
- @page_scale = args[:page_scale] || 1
177
- @page_width = args[:page_width] || 1169 # A4
178
- @page_height = args[:page_height] || 827 # A4
179
- @background = args[:background] || '#FFFACD'
180
- @page_shadow = args[:page_shadow] || 0
181
- @math = args[:math] || 0
182
-
183
- @style = DrawioDsl::Schema::CommonStyle.new(**args) do
184
- # Inherit from the diagram style when specific style not specified.
185
- @white_space ||= diagram.style.white_space
186
- @html ||= diagram.style.html
187
- @rounded ||= diagram.style.rounded
188
- @shadow ||= diagram.style.shadow
189
- @sketch ||= diagram.style.sketch
190
- @glass ||= diagram.style.glass
191
- end
192
-
193
- @palette = DrawioDsl::Schema::DefaultPalette.new(self, **args) do |page|
194
- theme_palette = KConfig.configuration.drawio.palette(page.theme)
195
-
196
- # Inherit from theme when specific palette options are not specified.
197
- @fill_color ||= theme_palette.fill_color
198
- @stroke_color ||= theme_palette.stroke_color
199
- @font_color ||= theme_palette.font_color
200
- @gradient ||= theme_palette.gradient
201
- end
202
-
203
- @nodes = args[:nodes] || []
204
- end
205
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
206
-
207
- def to_h
208
- {
209
- id: id,
210
- name: name,
211
- theme: theme,
212
- palette: palette.to_h,
213
- style: style.to_h,
214
- margin_left: margin_left,
215
- margin_top: margin_top,
216
- position_x: position_x,
217
- position_y: position_y,
218
- nodes: nodes.map(&:to_h)
219
- }
220
- end
221
- end
222
-
223
- # Node is a base for shapes, connections, positioners and layout rules
224
- class Node
225
- attr_accessor :id
226
- attr_accessor :page
227
- attr_accessor :classification
228
-
229
- def initialize(page, **args)
230
- @page = page
231
- @id = args[:id]
232
- @classification = args[:classification] || :unknown
233
- end
234
-
235
- def to_h
236
- {
237
- id: id,
238
- classification: classification
239
- }
240
- end
241
-
242
- def debug(format: :detail)
243
- if format == :detail
244
- debug_detail(to_h)
245
- else
246
- debug_row(classification, id)
247
- end
248
- end
249
-
250
- def debug_detail(**key_values)
251
- key_values.each do |key, value|
252
- puts "#{key.to_s.ljust(15)}: #{value}"
253
- end
254
- end
255
-
256
- # rubocop:disable Metrics/AbcSize, Metrics/ParameterLists
257
- def debug_row(classification, id, type = nil, x = nil, y = nil, width = nil, height = nil)
258
- row = []
259
- row << classification.to_s.ljust(11)
260
- row << id.to_s.ljust(6)
261
- row << (type.nil? ? '' : type).to_s.ljust(15)
262
- row << (x.nil? ? '' : x).to_s.rjust(5)
263
- row << (y.nil? ? '' : y).to_s.rjust(5)
264
- row << (width.nil? ? '' : width).to_s.rjust(5)
265
- row << (height.nil? ? '' : height).to_s.rjust(5)
266
- puts row.join(' | ')
267
- end
268
- # rubocop:enable Metrics/AbcSize, Metrics/ParameterLists
269
- end
270
-
271
- # Provides base configuration for automatic layouts
272
- class LayoutRule < Node
273
- attr_accessor :type
274
-
275
- # represents the x coordinate of the top left corner layout area
276
- # this coordinate is based on the current location of the page
277
- attr_accessor :anchor_x
278
- attr_accessor :anchor_y
279
-
280
- def initialize(page, **args)
281
- @after_init_fired = false
282
-
283
- super(page, **args.merge(classification: :layout_rule))
284
- end
285
-
286
- def fire_after_init
287
- return if @after_init_fired
288
-
289
- @after_init_fired = true
290
- after_init
291
- end
292
-
293
- def after_init
294
- @anchor_x ||= page.position_x
295
- @anchor_y ||= page.position_y
296
- end
297
-
298
- def to_h
299
- super.merge(
300
- type: type,
301
- anchor_x: anchor_x,
302
- anchor_y: anchor_y
303
- )
304
- end
305
- end
306
-
307
- # Provides grid style layouts
308
- class GridLayout < LayoutRule
309
- attr_accessor :direction
310
- attr_accessor :wrap_at
311
- attr_accessor :grid_size
312
- attr_accessor :cell_no
313
- attr_accessor :h_align
314
- attr_accessor :v_align
315
-
316
- def initialize(page, **args)
317
- @type = :grid_layout
318
- @direction = args[:direction] || :horizontal
319
- @wrap_at = args[:wrap_at] || 5
320
- @grid_size = args[:grid_size] || 220
321
- @h_align = args[:h_align] || :center
322
- @v_align = args[:v_align] || :center
323
- @cell_no = 1
324
-
325
- super(page, **args)
326
- end
327
-
328
- def position_shape(shape)
329
- fire_after_init
330
-
331
- shape.x = horizontal_shape_alignment(shape)
332
- shape.y = vertical_shape_alignment(shape)
333
-
334
- # puts '------------------'
335
- # puts "cell: #{cell_no}"
336
- # puts "wrap_at: #{wrap_at}"
337
- # puts "shape-x: #{shape.x}"
338
- # puts "shape-y: #{shape.y}"
339
- # puts "page-x: #{page.position_x}"
340
- # puts "page-y: #{page.position_y}"
341
- # puts "anchor-x: #{anchor_x}"
342
- # puts "anchor-y: #{anchor_y}"
343
-
344
- move_cell_horizontally if direction == :horizontal
345
- move_cell_vertically if direction == :vertical
346
- end
347
-
348
- def to_h
349
- super.merge(
350
- direction: direction,
351
- wrap_at: wrap_at,
352
- grid_size: grid_size,
353
- cell_no: cell_no
354
- )
355
- end
356
-
357
- private
358
-
359
- # rubocop:disable Metrics/AbcSize
360
- def horizontal_shape_alignment(shape)
361
- return page.position_x + ((grid_size - shape.w) / 2) if h_align == :left
362
- return page.position_x + (grid_size - shape.x) if v_align == :right
363
-
364
- page.position_x
365
- end
366
- # rubocop:enable Metrics/AbcSize
367
-
368
- # rubocop:disable Metrics/AbcSize
369
- def vertical_shape_alignment(shape)
370
- return page.position_y + ((grid_size - shape.h) / 2) if v_align == :middle
371
- return page.position_y + (grid_size - shape.h) if v_align == :bottom
372
-
373
- page.position_y
374
- end
375
- # rubocop:enable Metrics/AbcSize
376
-
377
- def move_cell_horizontally
378
- if cell_no >= wrap_at
379
- # Flow down to the next row
380
- page.position_x = anchor_x
381
- page.position_y += grid_size
382
- @cell_no = 1
383
- else
384
- page.position_x += grid_size
385
- @cell_no += 1
386
- end
387
- end
388
-
389
- def move_cell_vertically
390
- if cell_no >= wrap_at
391
- # Flow right to the next column
392
- page.position_y = anchor_y
393
- page.position_x += grid_size
394
- @cell_no = 0
395
- else
396
- page.position_y += grid_size
397
- @cell_no += 1
398
- end
399
- end
400
- end
401
-
402
- # Provides flex style layouts
403
- class FlexLayout < LayoutRule
404
- attr_accessor :direction
405
- attr_accessor :wrap_at
406
-
407
- def initialize(page, **args)
408
- @type = :flex_layout
409
- @direction = args[:direction] || :horizontal
410
- @wrap_at = args[:wrap_at] || (direction == :horizontal ? 1000 : 800)
411
-
412
- super(page, **args)
413
- end
414
-
415
- # rubocop:disable Metrics/AbcSize, Style/GuardClause
416
- def position_shape(shape)
417
- fire_after_init
418
-
419
- shape.x = page.position_x
420
- shape.y = page.position_y
421
-
422
- # Flow down to the next row
423
- if direction == :horizontal
424
- if page.position_x + shape.w > boundary
425
- page.position_x = anchor_x
426
- page.position_y += grid_size
427
- @cell_no = 0
428
- else
429
- page.position_x += grid_size
430
- end
431
- end
432
-
433
- # Flow right to the next column
434
- if direction == :vertical
435
- if page.position_y + shape.h > boundary
436
- page.position_y = anchor_y
437
- page.position_x += grid_size
438
- @cell_no = 0
439
- else
440
- page.position_y += grid_size
441
- end
442
- end
443
- end
444
- # rubocop:enable Metrics/AbcSize, Style/GuardClause
445
-
446
- private
447
-
448
- def boundary
449
- return @boundary if defined? @boundary
450
-
451
- bounds = grid_size * wrap_at
452
- @boundary = bounds + (direction == :horizontal ? anchor_x : anchor_y)
453
- end
454
-
455
- def to_h
456
- super.merge(direction: direction, wrap_at: wrap_at)
457
- end
458
- end
459
-
460
- # Shape is a graphical element, it can be a shape, a text, or a group (todo)
461
- class Shape < Node
462
- attr_accessor :theme
463
- attr_accessor :title
464
-
465
- # The style of the element, these will derive from the page style if not provided
466
- attr_accessor :white_space
467
- attr_accessor :html
468
- attr_accessor :rounded
469
- attr_accessor :shadow
470
- attr_accessor :glass
471
- attr_accessor :sketch
472
-
473
- attr_accessor :fill_color
474
- attr_accessor :stroke_color
475
- attr_accessor :font_color
476
- attr_accessor :gradient
477
-
478
- attr_accessor :type
479
- attr_accessor :x
480
- attr_accessor :y
481
- attr_accessor :w
482
- attr_accessor :h
483
- attr_accessor :style_modifiers
484
-
485
- def initialize(page, **args)
486
- args[:classification] = :shape
487
- super(page, **args)
488
-
489
- apply_defaults(args, KConfig.configuration.drawio.shape)
490
- end
491
-
492
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
493
- def apply_defaults(args, shape_defaults)
494
- @theme = args[:theme] || page.theme # KConfig.configuration.drawio.themes.sample
495
- theme_palette = KConfig.configuration.drawio.palette(page.theme)
496
- @title = args[:title] || ''
497
-
498
- @white_space = args[:white_space] || page.style.white_space # wrap or nil
499
- @html = args[:html] || page.style.html
500
- @rounded = args[:rounded] || page.style.rounded
501
- @shadow = args[:shadow] || page.style.shadow
502
- @sketch = args[:sketch] || page.style.sketch
503
- @glass = args[:glass] || page.style.glass
504
-
505
- @type = args[:type] || shape_defaults.type
506
- @x = args[:x] || shape_defaults.x
507
- @y = args[:y] || shape_defaults.y
508
- @w = args[:w] || shape_defaults.w
509
- @h = args[:h] || shape_defaults.h
510
- @style_modifiers = args[:style_modifiers] || shape_defaults.style_modifiers
511
-
512
- @fill_color = args[:fill_color] || theme_palette.fill_color
513
- @stroke_color = args[:stroke_color] || theme_palette.stroke_color
514
- @font_color = args[:font_color] || theme_palette.font_color
515
- @gradient = args[:gradient] || theme_palette.gradient
516
- end
517
-
518
- def style
519
- key_values = []
520
- key_values << style_modifiers unless style_modifiers.empty?
521
- key_values << "whiteSpace=#{white_space}" if white_space
522
- key_values << "html=#{html}" if html
523
- key_values << "rounded=#{rounded}" if rounded
524
- key_values << "shadow=#{shadow}" if shadow
525
- key_values << "sketch=#{sketch}" if sketch
526
- key_values << "glass=#{glass}" if glass
527
- key_values << "fillColor=#{fill_color}" if fill_color
528
- key_values << "strokeColor=#{stroke_color}" if stroke_color
529
- key_values << "fontColor=#{font_color}" if font_color
530
- key_values << "gradient=#{gradient}" if gradient
531
-
532
- key_values.join(';')
533
- end
534
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
535
-
536
- def to_h
537
- {
538
- id: id,
539
- classification: classification,
540
- type: type,
541
- x: x,
542
- y: y,
543
- w: w,
544
- h: h,
545
- style: style
546
- }
547
- end
548
-
549
- def debug(format: :detail)
550
- if format == :detail
551
- debug_detail({ id: id, classification: classification, type: type })
552
- else
553
- debug_row(classification, id, type, x, y, w, h)
554
- end
555
- end
556
- end
557
-
558
- # Graphical shape in the form of a square
559
- class Square < Shape
560
- def initialize(page, **args)
561
- super(page, **args)
562
-
563
- apply_defaults(args, KConfig.configuration.drawio.square)
564
- end
565
- end
566
-
567
- # Graphical shape in the form of a rectangle
568
- class Rectangle < Shape
569
- def initialize(page, **args)
570
- super(page, **args)
571
-
572
- apply_defaults(args, KConfig.configuration.drawio.rectangle)
573
- end
574
- end
575
-
576
- # Graphical shape in the form of a circle
577
- class Circle < Shape
578
- def initialize(page, **args)
579
- super(page, **args)
580
-
581
- apply_defaults(args, KConfig.configuration.drawio.circle)
582
- end
583
- end
584
-
585
- # Graphical shape in the form of an rectangle with to vertical lines
586
- class Process < Shape
587
- def initialize(page, **args)
588
- super(page, **args)
589
-
590
- apply_defaults(args, KConfig.configuration.drawio.process)
591
- end
592
- end
593
-
594
- # Graphical shape in the form of an ellipse
595
- class Ellipse < Shape
596
- def initialize(page, **args)
597
- super(page, **args)
598
-
599
- apply_defaults(args, KConfig.configuration.drawio.ellipse)
600
- end
601
- end
602
- end
603
- end
604
- # dx="800" dy="583" background="#FFFACD" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"