drawio_dsl 0.2.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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"