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 +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
|