drawio_dsl 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.builders/generators/10-layout.rb +15 -2
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +10 -0
- data/lib/drawio_dsl/configuration.rb +12 -12
- data/lib/drawio_dsl/dom_builder.rb +41 -23
- data/lib/drawio_dsl/drawio.rb +21 -41
- data/lib/drawio_dsl/layout_engine.rb +38 -26
- data/lib/drawio_dsl/schema.rb +306 -48
- data/lib/drawio_dsl/version.rb +1 -1
- data/lib/drawio_dsl/xml_builder.rb +7 -7
- data/lib/drawio_dsl.rb +0 -1
- data/package-lock.json +2 -2
- data/package.json +1 -1
- metadata +2 -3
- data/lib/drawio_dsl/layout_container.rb +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96f9176e2e3f9b37f0a02f462d075835aae641a43d14dc45c747a1434fcb17df
|
4
|
+
data.tar.gz: 07ef19170c1721bb9ebe7a58d9cc6d20ca000d620b555941c2e396d83a8b27e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
10
|
-
|
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
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
|
-
|
21
|
-
|
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
|
-
#
|
29
|
-
attr_accessor :
|
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
|
-
@
|
43
|
-
@square =
|
44
|
-
@rectangle =
|
45
|
-
@circle =
|
46
|
-
@process =
|
47
|
-
@ellipse =
|
48
|
-
@triangle =
|
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] =
|
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 :
|
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
|
-
|
59
|
-
|
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
|
-
|
80
|
+
shape.id = "#{current_page.id}-#{current_page.nodes.length + 1}" unless shape.id
|
62
81
|
|
63
|
-
|
82
|
+
current_page.nodes << shape
|
64
83
|
|
65
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
109
|
+
add_shape(ellipse)
|
92
110
|
end
|
93
111
|
|
94
112
|
def debug
|
data/lib/drawio_dsl/drawio.rb
CHANGED
@@ -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
|
77
|
-
builder.
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
25
|
-
|
26
|
-
|
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
|
-
|
33
|
-
|
31
|
+
apply_layout_to_page(page)
|
32
|
+
end
|
34
33
|
end
|
35
34
|
|
36
|
-
|
37
|
-
# def position_element(element)
|
38
|
-
# container.horizontal?
|
39
|
-
# end
|
35
|
+
private
|
40
36
|
|
41
|
-
|
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
|
-
|
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
|
-
|
55
|
+
def define_layout_rule(layout_rule)
|
56
|
+
layout_rule.debug
|
57
|
+
end
|
46
58
|
end
|
47
59
|
end
|
data/lib/drawio_dsl/schema.rb
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
module DrawioDsl
|
4
4
|
module Schema
|
5
|
-
# Common Style is the reused on Diagram, Page and
|
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
|
-
#
|
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]
|
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
|
89
|
-
@html
|
90
|
-
@rounded
|
91
|
-
@shadow
|
92
|
-
@sketch
|
93
|
-
@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
|
100
|
+
@fill_color ||= theme_palette.fill_color
|
101
101
|
@stroke_color ||= theme_palette.stroke_color
|
102
|
-
@font_color
|
103
|
-
@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
|
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 :
|
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
|
175
|
-
@html
|
176
|
-
@rounded
|
177
|
-
@shadow
|
178
|
-
@sketch
|
179
|
-
@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
|
197
|
+
@fill_color ||= theme_palette.fill_color
|
187
198
|
@stroke_color ||= theme_palette.stroke_color
|
188
|
-
@font_color
|
189
|
-
@gradient
|
199
|
+
@font_color ||= theme_palette.font_color
|
200
|
+
@gradient ||= theme_palette.gradient
|
190
201
|
end
|
191
202
|
|
192
|
-
@
|
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
|
-
|
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
|
-
#
|
209
|
-
class
|
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
|
-
|
238
|
-
|
486
|
+
args[:classification] = :shape
|
487
|
+
super(page, **args)
|
239
488
|
|
240
|
-
apply_defaults(args, KConfig.configuration.drawio.
|
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,
|
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] ||
|
257
|
-
@x = args[:x] ||
|
258
|
-
@y = args[:y] ||
|
259
|
-
@w = args[:w] ||
|
260
|
-
@h = args[:h] ||
|
261
|
-
@style_modifiers = args[: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
|
301
|
-
class Square <
|
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
|
310
|
-
class Rectangle <
|
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
|
319
|
-
class Circle <
|
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
|
328
|
-
class Process <
|
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
|
337
|
-
class Ellipse <
|
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
|
|
data/lib/drawio_dsl/version.rb
CHANGED
@@ -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.
|
56
|
-
|
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
|
64
|
+
def build_shape(xml, shape)
|
65
65
|
# puts "opts: #{opts}"
|
66
|
-
puts
|
67
|
-
puts
|
66
|
+
# puts shape.x
|
67
|
+
# puts shape.y
|
68
68
|
|
69
|
-
xml.mxCell(id:
|
70
|
-
xml.mxGeometry(x:
|
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.
|
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.
|
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
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.
|
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-
|
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
|