drawio_dsl 0.1.0 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6af520857fe09be7e990c254d75364ae3c4f145e77beb8aaf1850c7e99954666
4
- data.tar.gz: ed9f9debe4437765f426cb873cc226eb8721a89b2be257a30345122d59a25217
3
+ metadata.gz: 96f9176e2e3f9b37f0a02f462d075835aae641a43d14dc45c747a1434fcb17df
4
+ data.tar.gz: 07ef19170c1721bb9ebe7a58d9cc6d20ca000d620b555941c2e396d83a8b27e0
5
5
  SHA512:
6
- metadata.gz: 13a320ccac8daefe68036dafe8982451e28cb1ba56dd0be1b22694106fee82aa4625e8eee214a8a0cecdff476a5b2b56b90b45a6bbf8df82c1a315d36ea18a57
7
- data.tar.gz: 912a578341300d29b610fb053b5d4d98a161e7be9c1decd65b72af0398305a216d785245572b020b7463ad708ed74d6f7ddf936708175337eb6834f92611dcd8
6
+ metadata.gz: ccb338c21e1a14d55e0fb7965c05c014714e37081a1b2f365ea01168017d15327043255a23346dde6c7674419c5458ea9516411240108e5e5c4cb688b9210a9f
7
+ data.tar.gz: ab033223b347fa65e1e6e2ddb91d93085276052dd21685d5bd76db0c9cc0f92c1c0a2e5cade339f4e1f7a67569ee42153249d61ec6f15bdb8401e7b52d25d57b
@@ -5,9 +5,22 @@ KManager.action :bootstrap do
5
5
  on_exist: :skip, # %i[skip write compare]
6
6
  on_action: :queue # %i[queue execute]
7
7
  )
8
+ .diagram(theme: :style_01)
9
+ .page('Grid-Right', page_shadow: 1) do
10
+ grid_layout(wrap_at: 3)
11
+ square(title: 'Square')
12
+ rectangle(title: 'Rectangle')
13
+ rectangle(title: 'Rectangle (Rounded)', rounded: 1)
14
+ circle(title: 'Circle')
15
+ process(title: 'Process')
16
+ ellipse(title: 'Ellipse')
17
+ end
8
18
 
9
- File.write('spec/.samples/drawio/10-layout.xml', director.build)
10
- File.write('spec/.samples/drawio/10-layout.drawio', director.build)
19
+ diagram = DrawioDsl::XmlBuilder.new(director.builder.diagram)
20
+
21
+
22
+ File.write('../spec/.samples/drawio/10-layout.xml', diagram.build)
23
+ File.write('../spec/.samples/drawio/10-layout.drawio', diagram.build)
11
24
  end
12
25
  end
13
26
 
data/.rubocop.yml CHANGED
@@ -67,6 +67,10 @@ Naming/VariableNumber:
67
67
  Naming/MethodParameterName:
68
68
  AllowedNames:
69
69
  - as
70
+ - x
71
+ - y
72
+ - w
73
+ - h
70
74
  Style/EmptyMethod:
71
75
  Exclude:
72
76
  - "**/spec/**/*"
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ # [0.1.0](https://github.com/klueless-io/drawio_dsl/compare/v0.0.1...v0.1.0) (2022-03-02)
2
+
3
+
4
+ ### Features
5
+
6
+ * initial draw-io dsl ([ac197c8](https://github.com/klueless-io/drawio_dsl/commit/ac197c88b66b883b5fcce93090c285bc9ccdb7a3))
7
+ * initial draw-io dsl ([12c8b98](https://github.com/klueless-io/drawio_dsl/commit/12c8b98392e5f7da598cf2f9c375f1ca7041533b))
8
+ * initial draw-io dsl ([6ef32ad](https://github.com/klueless-io/drawio_dsl/commit/6ef32adcb1287d9993ebe30c437326716357a08e))
9
+ * initial draw-io dsl ([16827b5](https://github.com/klueless-io/drawio_dsl/commit/16827b57767d12c387167b86f17b33115d1d0378))
10
+
1
11
  ## [Unreleased]
2
12
 
3
13
  ## [0.1.0] - 2022-02-25
@@ -17,16 +17,16 @@ module DrawioDsl
17
17
 
18
18
  BaseStyle = Struct.new(:white_space, :html, :rounded, :shadow, :sketch, :glass, keyword_init: true)
19
19
 
20
- ElementDefaults = Struct.new(:type, :x, :y, :w, :h, :style_modifiers)
21
- ElementThemeStyle = Struct.new(:fill_color, :stroke_color, :font_color, :gradient, keyword_init: true)
20
+ ShapeDefaults = Struct.new(:type, :x, :y, :w, :h, :style_modifiers)
21
+ ShapeThemeStyle = Struct.new(:fill_color, :stroke_color, :font_color, :gradient, keyword_init: true)
22
22
 
23
23
  attr_accessor :base_style
24
24
 
25
25
  # Theme colors
26
26
  attr_accessor :themes
27
27
 
28
- # Element shapes
29
- attr_accessor :element
28
+ # Shape shapes
29
+ attr_accessor :shape
30
30
  attr_accessor :square
31
31
  attr_accessor :rectangle
32
32
  attr_accessor :circle
@@ -39,13 +39,13 @@ module DrawioDsl
39
39
  def initialize
40
40
  @base_style = BaseStyle.new(white_space: :wrap, html: 1, rounded: nil, shadow: nil, sketch: nil, glass: nil)
41
41
 
42
- @element = ElementDefaults.new(:element , 0, 0, 20, 20, '')
43
- @square = ElementDefaults.new(:square , 0, 0, 160, 160, '')
44
- @rectangle = ElementDefaults.new(:rectangle , 0, 0, 240, 120, '')
45
- @circle = ElementDefaults.new(:circle , 0, 0, 160, 160, 'ellipse')
46
- @process = ElementDefaults.new(:process , 0, 0, 240, 120, 'shape=process')
47
- @ellipse = ElementDefaults.new(:ellipse , 0, 0, 240, 120, 'ellipse')
48
- @triangle = ElementDefaults.new(:triangle , 0, 0, 160, 160, 'rhombus')
42
+ @shape = ShapeDefaults.new(:shape , 0, 0, 20, 20, '')
43
+ @square = ShapeDefaults.new(:square , 0, 0, 160, 160, '')
44
+ @rectangle = ShapeDefaults.new(:rectangle , 0, 0, 200, 120, '')
45
+ @circle = ShapeDefaults.new(:circle , 0, 0, 160, 160, 'ellipse')
46
+ @process = ShapeDefaults.new(:process , 0, 0, 200, 120, 'shape=process')
47
+ @ellipse = ShapeDefaults.new(:ellipse , 0, 0, 200, 120, 'ellipse')
48
+ @triangle = ShapeDefaults.new(:triangle , 0, 0, 160, 160, 'rhombus')
49
49
 
50
50
  @themes = {}
51
51
  add_themes
@@ -62,7 +62,7 @@ module DrawioDsl
62
62
  private
63
63
 
64
64
  def add_theme(name, **opts)
65
- @themes[name] = ElementThemeStyle.new(**opts)
65
+ @themes[name] = ShapeThemeStyle.new(**opts)
66
66
  end
67
67
 
68
68
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@@ -7,7 +7,8 @@ module DrawioDsl
7
7
  attr_reader :last_action
8
8
 
9
9
  attr_reader :current_page
10
- attr_reader :current_element
10
+ attr_reader :current_layout_rule
11
+ attr_reader :current_shape
11
12
 
12
13
  def initialize
13
14
  @actions = []
@@ -18,7 +19,7 @@ module DrawioDsl
18
19
  @actions = []
19
20
  @last_action = {}
20
21
  set_diagram
21
- set_layout_engine
22
+ # set_layout_engine
22
23
  end
23
24
 
24
25
  def queue_action(action)
@@ -26,16 +27,6 @@ module DrawioDsl
26
27
  @last_action = action
27
28
  end
28
29
 
29
- def set_layout_engine(**opts)
30
- @layout_engine = DrawioDsl::LayoutEngine.new(**opts)
31
- end
32
-
33
- def layout_engine
34
- return @layout_engine if defined? @layout_engine
35
-
36
- set_layout_engine
37
- end
38
-
39
30
  def set_diagram(**opts)
40
31
  @diagram = DrawioDsl::Schema::Diagram.new(**opts)
41
32
  end
@@ -55,40 +46,67 @@ module DrawioDsl
55
46
  @current_page
56
47
  end
57
48
 
58
- def add_element(element)
59
- @current_element = element
49
+ # ----------------------------------------------------------------------
50
+ # Layout provides rules for positioning components
51
+ # ----------------------------------------------------------------------
52
+
53
+ def add_grid_layout(**opts)
54
+ rule = DrawioDsl::Schema::GridLayout.new(current_page, **opts)
55
+ add_layout_rule(rule)
56
+ end
57
+
58
+ def add_flex_layout(**opts)
59
+ rule = DrawioDsl::Schema::FlexLayout.new(current_page, **opts)
60
+ add_layout_rule(rule)
61
+ end
62
+
63
+ def add_layout_rule(rule)
64
+ @current_layout_rule = rule
65
+
66
+ rule.id = "rule-#{current_page.nodes.length + 1}" unless rule.id
67
+
68
+ current_page.nodes << rule
69
+
70
+ rule
71
+ end
72
+
73
+ # ----------------------------------------------------------------------
74
+ # Shapes represent visual components
75
+ # ----------------------------------------------------------------------
76
+
77
+ def add_shape(shape)
78
+ @current_shape = shape
60
79
 
61
- element.id = "#{current_page.id}-#{current_page.elements.length + 1}" unless element.id
80
+ shape.id = "#{current_page.id}-#{current_page.nodes.length + 1}" unless shape.id
62
81
 
63
- layout_engine.container.place_element(element)
82
+ current_page.nodes << shape
64
83
 
65
- current_page.elements << element
66
- @current_element
84
+ shape
67
85
  end
68
86
 
69
87
  def add_square(**opts)
70
88
  square = DrawioDsl::Schema::Square.new(current_page, **opts)
71
- add_element(square)
89
+ add_shape(square)
72
90
  end
73
91
 
74
92
  def add_rectangle(**opts)
75
93
  rectangle = DrawioDsl::Schema::Rectangle.new(current_page, **opts)
76
- add_element(rectangle)
94
+ add_shape(rectangle)
77
95
  end
78
96
 
79
97
  def add_circle(**opts)
80
98
  circle = DrawioDsl::Schema::Circle.new(current_page, **opts)
81
- add_element(circle)
99
+ add_shape(circle)
82
100
  end
83
101
 
84
102
  def add_process(**opts)
85
103
  process = DrawioDsl::Schema::Process.new(current_page, **opts)
86
- add_element(process)
104
+ add_shape(process)
87
105
  end
88
106
 
89
107
  def add_ellipse(**opts)
90
108
  ellipse = DrawioDsl::Schema::Ellipse.new(current_page, **opts)
91
- add_element(ellipse)
109
+ add_shape(ellipse)
92
110
  end
93
111
 
94
112
  def debug
@@ -5,12 +5,6 @@ module DrawioDsl
5
5
  class Drawio < KDirector::Directors::BaseDirector
6
6
  default_builder_type(DrawioDsl::DomBuilder)
7
7
 
8
- def layout(**opts)
9
- builder.set_layout_engine(**opts)
10
-
11
- self
12
- end
13
-
14
8
  def diagram(**opts)
15
9
  builder.set_diagram(**opts)
16
10
 
@@ -23,6 +17,13 @@ module DrawioDsl
23
17
 
24
18
  self
25
19
  end
20
+
21
+ def apply_layout
22
+ engine = DrawioDsl::LayoutEngine.new(builder.diagram)
23
+ engine.call
24
+
25
+ self
26
+ end
26
27
  end
27
28
 
28
29
  # DrawioDsl::DrawioPage is created when you call .page on the draw-io DSL.
@@ -41,63 +42,42 @@ module DrawioDsl
41
42
  builder.add_page(**opts)
42
43
  end
43
44
 
45
+ def layout_rule(**opts)
46
+ builder.add_layout_rule(**opts)
47
+ end
48
+
49
+ def grid_layout(**opts)
50
+ builder.add_grid_layout(**opts)
51
+ end
52
+
53
+ def flex_layout(**opts)
54
+ builder.add_flex_layout(**opts)
55
+ end
56
+
44
57
  def square(**opts)
45
- opts = attach_xy(**opts)
46
58
  builder.add_square(**opts)
47
- update_layout
48
59
  end
49
60
 
50
61
  def rectangle(**opts)
51
- opts = attach_xy(**opts)
52
62
  builder.add_rectangle(**opts)
53
- update_layout
54
63
  end
55
64
 
56
65
  def circle(**opts)
57
- opts = attach_xy(**opts)
58
66
  builder.add_circle(**opts)
59
- update_layout
60
67
  end
61
68
 
62
69
  def process(**opts)
63
- opts = attach_xy(**opts)
64
70
  builder.add_process(**opts)
65
- update_layout
66
71
  end
67
72
 
68
73
  def ellipse(**opts)
69
- opts = attach_xy(**opts)
70
74
  builder.add_ellipse(**opts)
71
- update_layout
72
75
  end
73
76
 
74
77
  private
75
78
 
76
- def current_element
77
- builder.current_element
78
- end
79
-
80
- # attr_reader :layout_engine
81
- # set_layout
82
-
83
- # layout.container.place_element(element)
84
-
85
- def update_layout
86
- return unless auto_layout
87
-
88
- # puts current_element.page.x
89
- # puts current_element.page.y
90
- # puts current_element.page.w
91
- # puts current_element.page.h
92
-
93
- @current_x += current_element.w + 20
94
- @current_y += current_element.h + 20
95
- end
96
-
97
- def attach_xy(**opts)
98
- opts[:x] ||= current_x
99
- opts[:y] ||= current_y
100
- opts
79
+ def current_shape
80
+ builder.current_shape
101
81
  end
102
82
  end
103
83
  end
@@ -9,39 +9,51 @@ module DrawioDsl
9
9
  # Elements will be placed on the page in the order they are added.
10
10
  # Row/column flow objects will hold information about horizontal and vertical element padding
11
11
  class LayoutEngine
12
- attr_accessor :margin_left
13
- attr_accessor :margin_top
14
- attr_accessor :x
15
- attr_accessor :y
16
-
17
- def initialize(**opts)
18
- @margin_left = opts[:margin_left] || 20
19
- @margin_top = opts[:margin_top] || 20
20
- @x = opts[:x] || @margin_left
21
- @y = opts[:y] || @margin_top
12
+ attr_reader :diagram
13
+
14
+ attr_reader :current_page
15
+ attr_reader :current_layout
16
+ attr_reader :page_margin_top
17
+ attr_reader :page_margin_left
18
+ attr_reader :x
19
+ attr_reader :y
20
+
21
+ def initialize(diagram)
22
+ @diagram = diagram
23
+ @x = 0
24
+ @y = 0
22
25
  end
23
26
 
24
- def container
25
- @container ||= LayoutContainer.new(self)
26
- end
27
-
28
- def go_vertical(**opts)
29
- @container = LayoutContainer.new(self, direction: :vertical, **opts)
30
- end
27
+ def call
28
+ diagram.pages.each do |page|
29
+ focus_on_page(page)
31
30
 
32
- def go_horizontal(**opts)
33
- @container = LayoutContainer.new(self, direction: :horizontal, **opts)
31
+ apply_layout_to_page(page)
32
+ end
34
33
  end
35
34
 
36
- # # Position the incoming element by altering it's x, y coordinates based on the rules engine
37
- # def position_element(element)
38
- # container.horizontal?
39
- # end
35
+ private
40
36
 
41
- # private
37
+ def focus_on_page(page)
38
+ @current_page = page
39
+ page.position_x = page.margin_left
40
+ page.position_y = page.margin_top
41
+ end
42
42
 
43
- # def position_horizontally(element)
43
+ def apply_layout_to_page(page)
44
+ page.nodes.each do |node|
45
+ case node.classification
46
+ when :layout_rule
47
+ @current_layout = node
48
+ when :shape
49
+ current_layout.position_shape(node)
50
+ end
51
+ node.debug(format: :row)
52
+ end
53
+ end
44
54
 
45
- # end
55
+ def define_layout_rule(layout_rule)
56
+ layout_rule.debug
57
+ end
46
58
  end
47
59
  end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module DrawioDsl
4
4
  module Schema
5
- # Common Style is the reused on Diagram, Page and Element
5
+ # Common Style is the reused on Diagram, Page and Shape
6
6
  #
7
7
  # When styles are not provided at each level, then they will inherit from
8
8
  # the parent common style.
9
9
  #
10
- # Elements will use the common style of their page
10
+ # Shapes will use the common style of their page
11
11
  class CommonStyle
12
12
  attr_accessor :theme
13
13
  attr_accessor :white_space
@@ -76,7 +76,7 @@ module DrawioDsl
76
76
 
77
77
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
78
78
  def initialize(**args)
79
- @host = args[:host] || SecureRandom.alphanumeric(3)
79
+ @host = args[:host] || SecureRandom.alphanumeric(3)
80
80
 
81
81
  # Apply a random theme to the diagram if none is specified.
82
82
  @theme = args[:theme] || KConfig.configuration.drawio.random_theme
@@ -85,22 +85,22 @@ module DrawioDsl
85
85
  default_style = KConfig.configuration.drawio.base_style
86
86
 
87
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
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
94
  end
95
95
 
96
96
  @palette = DrawioDsl::Schema::DefaultPalette.new(self, **args) do |diagram|
97
97
  theme_palette = KConfig.configuration.drawio.palette(diagram.theme)
98
98
 
99
99
  # Inherit from theme when specific palette options are not specified.
100
- @fill_color ||= theme_palette.fill_color
100
+ @fill_color ||= theme_palette.fill_color
101
101
  @stroke_color ||= theme_palette.stroke_color
102
- @font_color ||= theme_palette.font_color
103
- @gradient ||= theme_palette.gradient
102
+ @font_color ||= theme_palette.font_color
103
+ @gradient ||= theme_palette.gradient
104
104
  end
105
105
 
106
106
  @pages = args[:pages] || []
@@ -118,16 +118,22 @@ module DrawioDsl
118
118
  end
119
119
  end
120
120
 
121
- # Page is a container for elements
121
+ # Page is a container for nodes
122
122
  class Page
123
123
  attr_accessor :diagram
124
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
+
125
129
  attr_accessor :id
126
130
  attr_accessor :name
127
131
  attr_accessor :theme
128
132
  attr_accessor :style
129
133
  attr_accessor :palette
130
- attr_accessor :elements
134
+ attr_accessor :margin_left
135
+ attr_accessor :margin_top
136
+ attr_accessor :nodes
131
137
 
132
138
  # attr_accessor :dx # dx = "2636"
133
139
  # attr_accessor :dy # dy = "2332"
@@ -150,9 +156,14 @@ module DrawioDsl
150
156
  def initialize(diagram, **args)
151
157
  @diagram = diagram
152
158
 
159
+ @position_x = 0
160
+ @position_y = 0
161
+
153
162
  @id = args[:id]
154
163
  @name = args[:name]
155
164
  @theme = args[:theme] || diagram.theme
165
+ @margin_left = args[:margin_left] || 50
166
+ @margin_top = args[:margin_top] || 50
156
167
 
157
168
  @grid = args[:grid] || 0
158
169
  @grid_size = args[:grid_size] || 10
@@ -171,25 +182,25 @@ module DrawioDsl
171
182
 
172
183
  @style = DrawioDsl::Schema::CommonStyle.new(**args) do
173
184
  # Inherit from the diagram style when specific style not specified.
174
- @white_space ||= diagram.style.white_space
175
- @html ||= diagram.style.html
176
- @rounded ||= diagram.style.rounded
177
- @shadow ||= diagram.style.shadow
178
- @sketch ||= diagram.style.sketch
179
- @glass ||= diagram.style.glass
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
180
191
  end
181
192
 
182
193
  @palette = DrawioDsl::Schema::DefaultPalette.new(self, **args) do |page|
183
194
  theme_palette = KConfig.configuration.drawio.palette(page.theme)
184
195
 
185
196
  # Inherit from theme when specific palette options are not specified.
186
- @fill_color ||= theme_palette.fill_color
197
+ @fill_color ||= theme_palette.fill_color
187
198
  @stroke_color ||= theme_palette.stroke_color
188
- @font_color ||= theme_palette.font_color
189
- @gradient ||= theme_palette.gradient
199
+ @font_color ||= theme_palette.font_color
200
+ @gradient ||= theme_palette.gradient
190
201
  end
191
202
 
192
- @elements = args[:elements] || []
203
+ @nodes = args[:nodes] || []
193
204
  end
194
205
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
195
206
 
@@ -200,15 +211,254 @@ module DrawioDsl
200
211
  theme: theme,
201
212
  palette: palette.to_h,
202
213
  style: style.to_h,
203
- elements: elements.map(&: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)
204
219
  }
205
220
  end
206
221
  end
207
222
 
208
- # Element is a graphical element, it can be a shape, a text, or a group (todo)
209
- class Element
223
+ # Node is a base for shapes, connections, positioners and layout rules
224
+ class Node
225
+ attr_accessor :id
210
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
211
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
212
462
  attr_accessor :theme
213
463
  attr_accessor :title
214
464
 
@@ -225,7 +475,6 @@ module DrawioDsl
225
475
  attr_accessor :font_color
226
476
  attr_accessor :gradient
227
477
 
228
- attr_accessor :id
229
478
  attr_accessor :type
230
479
  attr_accessor :x
231
480
  attr_accessor :y
@@ -234,14 +483,14 @@ module DrawioDsl
234
483
  attr_accessor :style_modifiers
235
484
 
236
485
  def initialize(page, **args)
237
- @page = page
238
- @id = args[:id]
486
+ args[:classification] = :shape
487
+ super(page, **args)
239
488
 
240
- apply_defaults(args, KConfig.configuration.drawio.element)
489
+ apply_defaults(args, KConfig.configuration.drawio.shape)
241
490
  end
242
491
 
243
492
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
244
- def apply_defaults(args, element_defaults)
493
+ def apply_defaults(args, shape_defaults)
245
494
  @theme = args[:theme] || page.theme # KConfig.configuration.drawio.themes.sample
246
495
  theme_palette = KConfig.configuration.drawio.palette(page.theme)
247
496
  @title = args[:title] || ''
@@ -253,12 +502,12 @@ module DrawioDsl
253
502
  @sketch = args[:sketch] || page.style.sketch
254
503
  @glass = args[:glass] || page.style.glass
255
504
 
256
- @type = args[:type] || element_defaults.type
257
- @x = args[:x] || element_defaults.x
258
- @y = args[:y] || element_defaults.y
259
- @w = args[:w] || element_defaults.w
260
- @h = args[:h] || element_defaults.h
261
- @style_modifiers = args[:style_modifiers] || element_defaults.style_modifiers
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
262
511
 
263
512
  @fill_color = args[:fill_color] || theme_palette.fill_color
264
513
  @stroke_color = args[:stroke_color] || theme_palette.stroke_color
@@ -287,6 +536,7 @@ module DrawioDsl
287
536
  def to_h
288
537
  {
289
538
  id: id,
539
+ classification: classification,
290
540
  type: type,
291
541
  x: x,
292
542
  y: y,
@@ -295,10 +545,18 @@ module DrawioDsl
295
545
  style: style
296
546
  }
297
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
298
556
  end
299
557
 
300
- # Graphical element in the shape of a square
301
- class Square < Element
558
+ # Graphical shape in the form of a square
559
+ class Square < Shape
302
560
  def initialize(page, **args)
303
561
  super(page, **args)
304
562
 
@@ -306,8 +564,8 @@ module DrawioDsl
306
564
  end
307
565
  end
308
566
 
309
- # Graphical element in the shape of a rectangle
310
- class Rectangle < Element
567
+ # Graphical shape in the form of a rectangle
568
+ class Rectangle < Shape
311
569
  def initialize(page, **args)
312
570
  super(page, **args)
313
571
 
@@ -315,8 +573,8 @@ module DrawioDsl
315
573
  end
316
574
  end
317
575
 
318
- # Graphical element in the shape of a circle
319
- class Circle < Element
576
+ # Graphical shape in the form of a circle
577
+ class Circle < Shape
320
578
  def initialize(page, **args)
321
579
  super(page, **args)
322
580
 
@@ -324,8 +582,8 @@ module DrawioDsl
324
582
  end
325
583
  end
326
584
 
327
- # Graphical element in the shape of an rectangle with to vertical lines
328
- class Process < Element
585
+ # Graphical shape in the form of an rectangle with to vertical lines
586
+ class Process < Shape
329
587
  def initialize(page, **args)
330
588
  super(page, **args)
331
589
 
@@ -333,8 +591,8 @@ module DrawioDsl
333
591
  end
334
592
  end
335
593
 
336
- # Graphical element in the shape of an ellipse
337
- class Ellipse < Element
594
+ # Graphical shape in the form of an ellipse
595
+ class Ellipse < Shape
338
596
  def initialize(page, **args)
339
597
  super(page, **args)
340
598
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DrawioDsl
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -52,8 +52,8 @@ module DrawioDsl
52
52
  xml.root do
53
53
  xml.mxCell(id: "#{page.id}-A")
54
54
  xml.mxCell(id: "#{page.id}-B", parent: "#{page.id}-A")
55
- page.elements.each do |element|
56
- build_element(xml, element)
55
+ page.nodes.each do |node|
56
+ build_shape(xml, node) if node.classification == :shape
57
57
  end
58
58
  end
59
59
  end
@@ -61,13 +61,13 @@ module DrawioDsl
61
61
  end
62
62
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/BlockLength
63
63
 
64
- def build_element(xml, element)
64
+ def build_shape(xml, shape)
65
65
  # puts "opts: #{opts}"
66
- puts element.x
67
- puts element.y
66
+ # puts shape.x
67
+ # puts shape.y
68
68
 
69
- xml.mxCell(id: element.id, value: element.title, style: element.style, vertex: 1, parent: "#{element.page.id}-B") do
70
- xml.mxGeometry(x: element.x, y: element.y, width: element.w, height: element.h, as: 'geometry')
69
+ xml.mxCell(id: shape.id, value: shape.title, style: shape.style, vertex: 1, parent: "#{shape.page.id}-B") do
70
+ xml.mxGeometry(x: shape.x, y: shape.y, width: shape.w, height: shape.h, as: 'geometry')
71
71
  end
72
72
  end
73
73
  end
data/lib/drawio_dsl.rb CHANGED
@@ -12,7 +12,6 @@ require_relative 'drawio_dsl/version'
12
12
  require_relative 'drawio_dsl/schema'
13
13
  require_relative 'drawio_dsl/dom_builder'
14
14
  require_relative 'drawio_dsl/xml_builder'
15
- require_relative 'drawio_dsl/layout_container'
16
15
  require_relative 'drawio_dsl/layout_engine'
17
16
  require_relative 'drawio_dsl/drawio'
18
17
 
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "drawio_dsl",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "drawio_dsl",
9
- "version": "0.1.0",
9
+ "version": "0.2.0",
10
10
  "devDependencies": {
11
11
  "@klueless-js/semantic-release-rubygem": "github:klueless-js/semantic-release-rubygem",
12
12
  "@semantic-release/changelog": "^6.0.1",
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drawio_dsl",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "DrawIO DSL can build DrawIO diagrams using a Domain Specific Language",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: drawio_dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-02 00:00:00.000000000 Z
11
+ date: 2022-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: k_config
@@ -95,7 +95,6 @@ files:
95
95
  - lib/drawio_dsl/dom_builder.rb
96
96
  - lib/drawio_dsl/drawio.rb
97
97
  - lib/drawio_dsl/drawio_dsl-OLD.x
98
- - lib/drawio_dsl/layout_container.rb
99
98
  - lib/drawio_dsl/layout_engine.rb
100
99
  - lib/drawio_dsl/schema.rb
101
100
  - lib/drawio_dsl/version.rb
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DrawioDsl
4
- # The layout engine is responsible for laying out the elements on the page.
5
- #
6
- # The layout engine can automatically place elements on the page.
7
- #
8
- # It will keep track of layout boundaries, current position and flow direction.
9
- # Elements are positioned on the page in the order they are added.
10
- # Row/column flow objects will hold information about horizontal and vertical element padding
11
- class LayoutContainer
12
- DEFAULT_DIRECTION = :vertical
13
- DEFAULT_PADDING = 20
14
- DEFAULT_BOUNDARY_HEIGHT = 800
15
- DEFAULT_BOUNDARY_WIDTH = 1000
16
-
17
- attr_reader :engine
18
- attr_accessor :direction
19
- attr_accessor :padding
20
-
21
- def initialize(engine, **opts)
22
- @engine = engine
23
- @direction = opts[:direction] || DEFAULT_DIRECTION
24
- @padding = opts[:padding] || DEFAULT_PADDING
25
- @boundary = opts[:boundary]
26
- end
27
-
28
- def vertical?
29
- @direction == :vertical
30
- end
31
-
32
- def horizontal?
33
- @direction == :horizontal
34
- end
35
-
36
- attr_writer :boundary
37
-
38
- def boundary
39
- @boundary ||= (vertical? ? DEFAULT_BOUNDARY_HEIGHT : DEFAULT_BOUNDARY_WIDTH)
40
- end
41
-
42
- # Place the incoming element by altering it's x, y coordinates based on the rules engine
43
- def place_element(element)
44
- place_vertical(element) if vertical?
45
- end
46
-
47
- def place_vertical(element)
48
- element.x = engine.x
49
- element.y = engine.y
50
-
51
- engine.y += (element.h + padding)
52
- end
53
- end
54
- end