archimate 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.projectile +18 -0
  4. data/.rubocop.yml +13 -0
  5. data/.travis.yml +4 -0
  6. data/.yardocs +15 -0
  7. data/Gemfile +5 -0
  8. data/Guardfile +27 -0
  9. data/LICENSE +201 -0
  10. data/README.md +94 -0
  11. data/Rakefile +29 -0
  12. data/TODOs.org +286 -0
  13. data/archimate.gemspec +51 -0
  14. data/bin/archimate +17 -0
  15. data/bin/console +13 -0
  16. data/bin/setup +8 -0
  17. data/exe/archidiff +7 -0
  18. data/exe/archidiff-summary +7 -0
  19. data/exe/archimate +7 -0
  20. data/exe/archimerge +7 -0
  21. data/exe/fmtxml +7 -0
  22. data/lib/archimate/cli/archi.rb +189 -0
  23. data/lib/archimate/cli/cleanup.rb +54 -0
  24. data/lib/archimate/cli/conflict_resolver.rb +39 -0
  25. data/lib/archimate/cli/convert.rb +39 -0
  26. data/lib/archimate/cli/diff.rb +31 -0
  27. data/lib/archimate/cli/diff_summary.rb +101 -0
  28. data/lib/archimate/cli/duper.rb +85 -0
  29. data/lib/archimate/cli/lint.rb +16 -0
  30. data/lib/archimate/cli/mapper.rb +82 -0
  31. data/lib/archimate/cli/merge.rb +49 -0
  32. data/lib/archimate/cli/merger.rb +109 -0
  33. data/lib/archimate/cli/stats.rb +42 -0
  34. data/lib/archimate/cli/svger.rb +40 -0
  35. data/lib/archimate/color.rb +53 -0
  36. data/lib/archimate/config.rb +35 -0
  37. data/lib/archimate/data_model/any_attribute.rb +13 -0
  38. data/lib/archimate/data_model/any_element.rb +15 -0
  39. data/lib/archimate/data_model/archimate_node.rb +181 -0
  40. data/lib/archimate/data_model/bounds.rb +72 -0
  41. data/lib/archimate/data_model/color.rb +47 -0
  42. data/lib/archimate/data_model/concept.rb +14 -0
  43. data/lib/archimate/data_model/concern.rb +17 -0
  44. data/lib/archimate/data_model/connection.rb +107 -0
  45. data/lib/archimate/data_model/constants.rb +82 -0
  46. data/lib/archimate/data_model/container.rb +17 -0
  47. data/lib/archimate/data_model/diagram.rb +40 -0
  48. data/lib/archimate/data_model/diffable_array.rb +213 -0
  49. data/lib/archimate/data_model/diffable_primitive.rb +83 -0
  50. data/lib/archimate/data_model/documentation.rb +14 -0
  51. data/lib/archimate/data_model/element.rb +87 -0
  52. data/lib/archimate/data_model/font.rb +54 -0
  53. data/lib/archimate/data_model/label.rb +19 -0
  54. data/lib/archimate/data_model/lang_string.rb +41 -0
  55. data/lib/archimate/data_model/location.rb +31 -0
  56. data/lib/archimate/data_model/metadata.rb +14 -0
  57. data/lib/archimate/data_model/model.rb +217 -0
  58. data/lib/archimate/data_model/modeling_note.rb +13 -0
  59. data/lib/archimate/data_model/named_referenceable.rb +14 -0
  60. data/lib/archimate/data_model/organization.rb +40 -0
  61. data/lib/archimate/data_model/property.rb +25 -0
  62. data/lib/archimate/data_model/property_definition.rb +16 -0
  63. data/lib/archimate/data_model/referenceable.rb +29 -0
  64. data/lib/archimate/data_model/relationship.rb +85 -0
  65. data/lib/archimate/data_model/schema_info.rb +18 -0
  66. data/lib/archimate/data_model/style.rb +32 -0
  67. data/lib/archimate/data_model/view.rb +12 -0
  68. data/lib/archimate/data_model/view_concept.rb +18 -0
  69. data/lib/archimate/data_model/view_node.rb +114 -0
  70. data/lib/archimate/data_model/viewpoint.rb +87 -0
  71. data/lib/archimate/data_model.rb +54 -0
  72. data/lib/archimate/diff/archimate_array_reference.rb +113 -0
  73. data/lib/archimate/diff/archimate_identified_node_reference.rb +41 -0
  74. data/lib/archimate/diff/archimate_node_attribute_reference.rb +70 -0
  75. data/lib/archimate/diff/archimate_node_reference.rb +80 -0
  76. data/lib/archimate/diff/change.rb +49 -0
  77. data/lib/archimate/diff/conflict.rb +31 -0
  78. data/lib/archimate/diff/conflicts/base_conflict.rb +53 -0
  79. data/lib/archimate/diff/conflicts/deleted_items_child_updated_conflict.rb +30 -0
  80. data/lib/archimate/diff/conflicts/deleted_items_referenced_conflict.rb +63 -0
  81. data/lib/archimate/diff/conflicts/path_conflict.rb +51 -0
  82. data/lib/archimate/diff/conflicts.rb +89 -0
  83. data/lib/archimate/diff/delete.rb +41 -0
  84. data/lib/archimate/diff/difference.rb +113 -0
  85. data/lib/archimate/diff/insert.rb +43 -0
  86. data/lib/archimate/diff/merge.rb +70 -0
  87. data/lib/archimate/diff/move.rb +51 -0
  88. data/lib/archimate/diff.rb +17 -0
  89. data/lib/archimate/export/csv_export.rb +32 -0
  90. data/lib/archimate/export/cypher.rb +171 -0
  91. data/lib/archimate/export/graph_ml.rb +131 -0
  92. data/lib/archimate/export/n_quads.rb +142 -0
  93. data/lib/archimate/file_format.rb +30 -0
  94. data/lib/archimate/file_formats/archi_file_format.rb +151 -0
  95. data/lib/archimate/file_formats/archi_file_reader.rb +252 -0
  96. data/lib/archimate/file_formats/archi_file_writer.rb +230 -0
  97. data/lib/archimate/file_formats/archimate_v2.rb +461 -0
  98. data/lib/archimate/file_formats/model_exchange_file/xml_lang_string.rb +35 -0
  99. data/lib/archimate/file_formats/model_exchange_file/xml_metadata.rb +115 -0
  100. data/lib/archimate/file_formats/model_exchange_file/xml_property_definitions.rb +28 -0
  101. data/lib/archimate/file_formats/model_exchange_file/xml_property_defs.rb +27 -0
  102. data/lib/archimate/file_formats/model_exchange_file_reader.rb +237 -0
  103. data/lib/archimate/file_formats/model_exchange_file_reader_21.rb +73 -0
  104. data/lib/archimate/file_formats/model_exchange_file_reader_30.rb +134 -0
  105. data/lib/archimate/file_formats/model_exchange_file_writer.rb +157 -0
  106. data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +143 -0
  107. data/lib/archimate/file_formats/model_exchange_file_writer_30.rb +153 -0
  108. data/lib/archimate/file_formats/writer.rb +56 -0
  109. data/lib/archimate/lint/duplicate_entities.rb +121 -0
  110. data/lib/archimate/lint/linter.rb +146 -0
  111. data/lib/archimate/logging.rb +55 -0
  112. data/lib/archimate/maybe_io.rb +34 -0
  113. data/lib/archimate/progress_indicator.rb +29 -0
  114. data/lib/archimate/svg/archimate.css +232 -0
  115. data/lib/archimate/svg/child.rb +29 -0
  116. data/lib/archimate/svg/connection.rb +184 -0
  117. data/lib/archimate/svg/css_style.rb +31 -0
  118. data/lib/archimate/svg/diagram.rb +87 -0
  119. data/lib/archimate/svg/entity/and_junction.rb +14 -0
  120. data/lib/archimate/svg/entity/application_collaboration.rb +14 -0
  121. data/lib/archimate/svg/entity/application_component.rb +41 -0
  122. data/lib/archimate/svg/entity/application_event.rb +13 -0
  123. data/lib/archimate/svg/entity/application_function.rb +13 -0
  124. data/lib/archimate/svg/entity/application_interaction.rb +13 -0
  125. data/lib/archimate/svg/entity/application_interface.rb +13 -0
  126. data/lib/archimate/svg/entity/application_process.rb +13 -0
  127. data/lib/archimate/svg/entity/application_service.rb +13 -0
  128. data/lib/archimate/svg/entity/artifact.rb +39 -0
  129. data/lib/archimate/svg/entity/assessment.rb +14 -0
  130. data/lib/archimate/svg/entity/base_entity.rb +128 -0
  131. data/lib/archimate/svg/entity/business_actor.rb +14 -0
  132. data/lib/archimate/svg/entity/business_collaboration.rb +14 -0
  133. data/lib/archimate/svg/entity/business_event.rb +10 -0
  134. data/lib/archimate/svg/entity/business_function.rb +13 -0
  135. data/lib/archimate/svg/entity/business_interaction.rb +13 -0
  136. data/lib/archimate/svg/entity/business_interface.rb +13 -0
  137. data/lib/archimate/svg/entity/business_object.rb +13 -0
  138. data/lib/archimate/svg/entity/business_process.rb +13 -0
  139. data/lib/archimate/svg/entity/business_role.rb +14 -0
  140. data/lib/archimate/svg/entity/business_service.rb +13 -0
  141. data/lib/archimate/svg/entity/capability.rb +14 -0
  142. data/lib/archimate/svg/entity/communication_network.rb +14 -0
  143. data/lib/archimate/svg/entity/communication_path.rb +14 -0
  144. data/lib/archimate/svg/entity/constraint.rb +15 -0
  145. data/lib/archimate/svg/entity/contract.rb +13 -0
  146. data/lib/archimate/svg/entity/course_of_action.rb +14 -0
  147. data/lib/archimate/svg/entity/data_entity.rb +29 -0
  148. data/lib/archimate/svg/entity/data_object.rb +13 -0
  149. data/lib/archimate/svg/entity/deliverable.rb +13 -0
  150. data/lib/archimate/svg/entity/device.rb +48 -0
  151. data/lib/archimate/svg/entity/diagram_model_reference.rb +22 -0
  152. data/lib/archimate/svg/entity/diagram_object.rb +30 -0
  153. data/lib/archimate/svg/entity/distribution_network.rb +14 -0
  154. data/lib/archimate/svg/entity/driver.rb +14 -0
  155. data/lib/archimate/svg/entity/equipment.rb +16 -0
  156. data/lib/archimate/svg/entity/event_entity.rb +36 -0
  157. data/lib/archimate/svg/entity/facility.rb +16 -0
  158. data/lib/archimate/svg/entity/function_entity.rb +14 -0
  159. data/lib/archimate/svg/entity/gap.rb +21 -0
  160. data/lib/archimate/svg/entity/goal.rb +14 -0
  161. data/lib/archimate/svg/entity/group.rb +24 -0
  162. data/lib/archimate/svg/entity/implementation_event.rb +13 -0
  163. data/lib/archimate/svg/entity/infrastructure_function.rb +13 -0
  164. data/lib/archimate/svg/entity/infrastructure_interface.rb +13 -0
  165. data/lib/archimate/svg/entity/infrastructure_service.rb +13 -0
  166. data/lib/archimate/svg/entity/interaction_entity.rb +14 -0
  167. data/lib/archimate/svg/entity/interface_entity.rb +35 -0
  168. data/lib/archimate/svg/entity/junction.rb +19 -0
  169. data/lib/archimate/svg/entity/location.rb +14 -0
  170. data/lib/archimate/svg/entity/material.rb +14 -0
  171. data/lib/archimate/svg/entity/meaning.rb +40 -0
  172. data/lib/archimate/svg/entity/motivation_entity.rb +40 -0
  173. data/lib/archimate/svg/entity/network.rb +14 -0
  174. data/lib/archimate/svg/entity/node.rb +33 -0
  175. data/lib/archimate/svg/entity/node_shape.rb +64 -0
  176. data/lib/archimate/svg/entity/note.rb +30 -0
  177. data/lib/archimate/svg/entity/or_junction.rb +14 -0
  178. data/lib/archimate/svg/entity/outcome.rb +15 -0
  179. data/lib/archimate/svg/entity/path.rb +14 -0
  180. data/lib/archimate/svg/entity/plateau.rb +15 -0
  181. data/lib/archimate/svg/entity/principle.rb +15 -0
  182. data/lib/archimate/svg/entity/process_entity.rb +63 -0
  183. data/lib/archimate/svg/entity/product.rb +20 -0
  184. data/lib/archimate/svg/entity/rect.rb +13 -0
  185. data/lib/archimate/svg/entity/rect_entity.rb +25 -0
  186. data/lib/archimate/svg/entity/representation.rb +31 -0
  187. data/lib/archimate/svg/entity/requirement.rb +15 -0
  188. data/lib/archimate/svg/entity/resource.rb +14 -0
  189. data/lib/archimate/svg/entity/rounded_rect_entity.rb +23 -0
  190. data/lib/archimate/svg/entity/service_entity.rb +51 -0
  191. data/lib/archimate/svg/entity/sketch_model_sticky.rb +14 -0
  192. data/lib/archimate/svg/entity/stakeholder.rb +15 -0
  193. data/lib/archimate/svg/entity/system_software.rb +14 -0
  194. data/lib/archimate/svg/entity/technology_collaboration.rb +14 -0
  195. data/lib/archimate/svg/entity/technology_event.rb +13 -0
  196. data/lib/archimate/svg/entity/technology_function.rb +13 -0
  197. data/lib/archimate/svg/entity/technology_interaction.rb +13 -0
  198. data/lib/archimate/svg/entity/technology_interface.rb +13 -0
  199. data/lib/archimate/svg/entity/technology_process.rb +13 -0
  200. data/lib/archimate/svg/entity/technology_service.rb +13 -0
  201. data/lib/archimate/svg/entity/value.rb +27 -0
  202. data/lib/archimate/svg/entity/work_package.rb +14 -0
  203. data/lib/archimate/svg/entity.rb +93 -0
  204. data/lib/archimate/svg/entity_factory.rb +17 -0
  205. data/lib/archimate/svg/extents.rb +27 -0
  206. data/lib/archimate/svg/point.rb +7 -0
  207. data/lib/archimate/svg/svg_template.rb +27 -0
  208. data/lib/archimate/svg/svg_template.svg.erb +169 -0
  209. data/lib/archimate/version.rb +4 -0
  210. data/lib/archimate.rb +114 -0
  211. metadata +623 -0
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ ## This class passes an IO (or a fake IO) to the given block based on passing
3
+ # either a filename to permit ouput into or nil for a fake IO.
4
+ #
5
+ module Archimate
6
+ class MaybeIO
7
+ # Creates a MaybeIO object passing it yielding it to the given block
8
+ #
9
+ # @param filename [String, nil] determines the IO yielded to the given block
10
+ # String: filename to make writable IO for
11
+ # nil: - A fake IO
12
+ # @yieldparam [IO] the given block gets an IO (or fake IO)
13
+ #
14
+ # @example Usage
15
+ # Archimate::MaybeIO.new(myfile) do |io|
16
+ # io.write("Writing away")
17
+ # end
18
+ def initialize(filename)
19
+ if filename.nil?
20
+ yield self
21
+ else
22
+ File.open(filename, "w") do |io|
23
+ yield io
24
+ end
25
+ end
26
+ end
27
+
28
+ # Implementation of the NilIO write method - effectively passes the input
29
+ # String to /dev/null
30
+ #
31
+ # @param _str [String] - unused, no effect
32
+ def write(_str); end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby-progressbar"
4
+
5
+ module Archimate
6
+ class ProgressIndicator
7
+ class FakeProgressBar
8
+ def increment; end
9
+
10
+ def finish; end
11
+ end
12
+
13
+ def initialize(total: 100, title: "ArchiMate!")
14
+ @progress = if Config.instance.interactive
15
+ ProgressBar.create(total: total, title: title, throttle_rate: 0.5)
16
+ else
17
+ FakeProgressBar.new
18
+ end
19
+ end
20
+
21
+ def increment
22
+ @progress.increment
23
+ end
24
+
25
+ def finish
26
+ @progress.finish
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,232 @@
1
+ svg {
2
+ font-family: "Lucida Grande";
3
+ font-size: 11px;
4
+ }
5
+
6
+ p {
7
+ fill: black;
8
+ margin: 0;
9
+ stroke: none;
10
+ }
11
+
12
+ path {
13
+ fill: inherit;
14
+ stroke: inherit;
15
+ stroke-width: 1px;
16
+ }
17
+
18
+ .entity-name {
19
+ text-align: center;
20
+ vertical-align: top;
21
+ }
22
+
23
+ .entity>.properties {
24
+ visibility: hidden;
25
+ }
26
+
27
+ .entity:hover>.properties {
28
+ visibility: visible;
29
+ z-index: 1000;
30
+ }
31
+
32
+ table.properties {
33
+ background-color: whitesmoke;
34
+ border: 2px solid gray;
35
+ }
36
+
37
+ table.properties>caption {
38
+ background-color: gray;
39
+ border: 2px solid gray;
40
+ border-top-left-radius: 8px;
41
+ border-top-right-radius: 8px;
42
+ }
43
+
44
+ .archimate-decoration {
45
+ fill:rgba(0,0,0,0.1);
46
+ stroke: inherit;
47
+ }
48
+
49
+ .archimate-badge {
50
+ fill: none;
51
+ stroke: black;
52
+ stroke-width: 1px;
53
+ }
54
+
55
+ .archimate-badge-spacer {
56
+ float: right;
57
+ height: 20px;
58
+ width: 20px;
59
+ /*border: 1px solid red;*/
60
+ }
61
+
62
+ .archimate-icon {
63
+ fill: none;
64
+ stroke: black;
65
+ }
66
+
67
+ .archimate-default-element {
68
+ fill: #ddd;
69
+ stroke: #999;
70
+ }
71
+
72
+ .archimate-strategy-background {
73
+ fill: #eddfac;
74
+ stroke: #44423b;
75
+ }
76
+
77
+ .archimate-business-background {
78
+ fill: #fffeb9;
79
+ stroke: #b2b181;
80
+ }
81
+
82
+ .archimate-business-decoration {
83
+ fill: rgb(229, 229, 162);
84
+ stroke: rgb(178, 178, 126);
85
+ }
86
+
87
+ .archimate-application-background {
88
+ fill: #ccfdfe;
89
+ stroke: #80b2b2;
90
+ }
91
+
92
+ .archimate-application-decoration {
93
+ fill: rgb(162, 229, 229);
94
+ stroke: rgb(126, 178, 178);
95
+ }
96
+
97
+ .archimate-infrastructure-background {
98
+ fill: #cae6b9;
99
+ stroke: #8ca081;
100
+ }
101
+
102
+ .archimate-infrastructure-decoration {
103
+ fill: #b4cfa4;
104
+ stroke: #9bb28d;
105
+ }
106
+
107
+ .archimate-physical-background {
108
+ fill: #cdfeb2;
109
+ stoke: #313331;
110
+ }
111
+
112
+ .archimate-motivation-background {
113
+ fill: #fecdfe;
114
+ stroke: #b18fb1;
115
+ }
116
+
117
+ .archimate-motivation2-background {
118
+ fill: #cccdfd;
119
+ stroke: #8e8fb1;
120
+ }
121
+
122
+ .archimate-implementation-background {
123
+ fill: #fee0e0;
124
+ stroke: #b19c9c;
125
+ }
126
+
127
+ .archimate-implementation2-background {
128
+ fill: #e0ffe0;
129
+ stroke: #9cb29c;
130
+ }
131
+
132
+ .archimate-implementation2-decoration {
133
+ fill: #c9e5c9;
134
+ stroke: #9cb29c;
135
+ }
136
+
137
+ .archimate-note-background {
138
+ fill: #fff;
139
+ stroke: #b2b2b2;
140
+ }
141
+
142
+ .archimate-group-background {
143
+ fill: #d2d7d7;
144
+ stroke: #939696;
145
+ }
146
+
147
+ .archimate-sticky-background {
148
+ fill: #fffeb9;
149
+ stroke: #b2b181;
150
+ }
151
+
152
+ .archimate-junction-background {
153
+ fill: black;
154
+ stroke: black;
155
+ }
156
+
157
+ .archimate-or-junction-background {
158
+ fill: white;
159
+ stroke: black;
160
+ }
161
+
162
+ .archimate-diagram-model-reference-background {
163
+ fill: #dcebeb;
164
+ stroke: #9aa4a4;
165
+ }
166
+
167
+ .archimate-default-background {
168
+ fill: #ddd;
169
+ stroke: #999;
170
+ }
171
+
172
+ /* Relationships */
173
+ .archimate-relationship {
174
+ fill: none;
175
+ stroke: black;
176
+ stroke-width: 1px;
177
+ }
178
+
179
+ .archimate-relationship-name {
180
+ font-size: 9px;
181
+ }
182
+
183
+ .archimate-assignment-relationship {
184
+ marker-end: url(#archimate-dot-marker);
185
+ marker-start: url(#archimate-dot-marker);
186
+ }
187
+
188
+ .archimate-composition-relationship {
189
+ marker-start: url(#archimate-filled-diamond);
190
+ }
191
+
192
+ .archimate-used-by-relationship {
193
+ marker-end: url(#archimate-used-by-arrow);
194
+ }
195
+
196
+ .archimate-serving-relationship {
197
+ marker-end: url(#archimate-used-by-arrow);
198
+ }
199
+
200
+ .archimate-aggregation-relationship {
201
+ marker-start: url(#archimate-hollow-diamond);
202
+ }
203
+
204
+ .archimate-access-relationship {
205
+ marker-end: url(#archimate-open-arrow);
206
+ stroke-dasharray: 2, 3;
207
+ }
208
+
209
+ .archimate-realisation-relationship {
210
+ marker-end: url(#archimate-hollow-arrow);
211
+ stroke-dasharray: 5, 3;
212
+ }
213
+
214
+ .archimate-specialisation-relationship {
215
+ marker-end: url(#archimate-hollow-arrow);
216
+ }
217
+
218
+ /*.archimate-influence-relationship, .archimate-association-relationship {
219
+ }
220
+ */
221
+ .archimate-triggering-relationship {
222
+ marker-end: url(#archimate-filled-arrow);
223
+ }
224
+
225
+ .archimate-flow-relationship {
226
+ marker-end: url(#archimate-filled-arrow);
227
+ stroke-dasharray: 3, 3;
228
+ }
229
+
230
+ /*.archimate-default-connection {
231
+ }
232
+ */
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ class Child
6
+ attr_reader :todos
7
+ attr_reader :child
8
+
9
+ def initialize(child)
10
+ @child = child
11
+ @todos = Hash.new(0)
12
+ end
13
+
14
+ # The info needed to render is contained in the child with the exception of
15
+ # any offset needed. So this will need to be included in the recursive drawing of children
16
+ def render_elements(svg)
17
+ Nokogiri::XML::Builder.with(svg) do |xml|
18
+ entity = EntityFactory.make_entity(child, nil)
19
+ if entity.nil?
20
+ puts "Unable to make an SVG Entity for Child:\n#{child}"
21
+ else
22
+ entity.to_svg(xml)
23
+ end
24
+ end
25
+ svg
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ class Connection
6
+ attr_reader :connection
7
+ attr_reader :css_style
8
+
9
+ def initialize(connection)
10
+ @connection = connection
11
+ @css_style = CssStyle.new(connection.style)
12
+ end
13
+
14
+ def render(svg)
15
+ Nokogiri::XML::Builder.with(svg) do |xml|
16
+ to_svg(xml)
17
+ end
18
+ svg
19
+ end
20
+
21
+ def to_svg(xml)
22
+ return if connection.source_element.nodes.include?(connection.target_element)
23
+ xml.path(path_attrs) do
24
+ xml.title @connection.description
25
+ end
26
+
27
+ name = connection&.relationship_element&.name&.strip
28
+ return if name.nil? || name.empty?
29
+ xml.text_(
30
+ class: "archimate-relationship-name",
31
+ dy: -2,
32
+ "text-anchor" => "middle",
33
+ style: css_style.text
34
+ ) do
35
+ xml.textPath(startOffset: text_position, "xlink:href" => "##{id}") do
36
+ xml.text name
37
+ end
38
+ end
39
+ end
40
+
41
+ def line_style
42
+ style = connection.style
43
+ return "" if style.nil?
44
+ {
45
+ "stroke": style.line_color&.to_rgba,
46
+ "stroke-width": style.line_width
47
+ }.delete_if { |_key, value| value.nil? }
48
+ .map { |key, value| "#{key}:#{value};" }
49
+ .join("")
50
+ end
51
+
52
+ def text_position
53
+ case connection.style
54
+ when 0
55
+ "10%"
56
+ when 1
57
+ "90%"
58
+ else
59
+ "50%"
60
+ end
61
+ end
62
+
63
+ def path_attrs
64
+ {
65
+ id: id,
66
+ class: path_class,
67
+ d: path_d,
68
+ style: line_style
69
+ }
70
+ end
71
+
72
+ def id
73
+ connection.relationship_element&.id || connection.id
74
+ end
75
+
76
+ # Look at the type (if any of the path and set the class appropriately)
77
+ def path_class
78
+ [
79
+ "archimate",
80
+ css_classify(connection&.relationship_element&.type || "default")
81
+ ].join("-") + " archimate-relationship"
82
+ end
83
+
84
+ # TODO: StringRefinements refinement isn't working in this class, so added this method here. Investigate.
85
+ def css_classify(str)
86
+ str.gsub(/::/, '/')
87
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1-\2')
88
+ .gsub(/([a-z\d])([A-Z])/, '\1-\2')
89
+ .downcase
90
+ end
91
+
92
+ def ranges_overlap(r1, r2)
93
+ begin_max = [r1, r2].map(&:begin).max
94
+ end_min = [r1, r2].map(&:end).min
95
+ return nil if begin_max > end_min
96
+ (begin_max + end_min) / 2.0
97
+ end
98
+
99
+ # builds the line coordinates for the path
100
+ # rough drawing is the point at center of first element, point of each bendpoint, and center of end element
101
+ # First naive implementation
102
+ # if left/right range of both overlap, use centerpoint of overlap range as x val
103
+ # if top/bottom range of both overlap, use centerpoint of overlap range as y val
104
+ def path_d
105
+ source_bounds = connection.source_element&.absolute_position || DataModel::Bounds.zero
106
+ target_bounds = connection.target_element&.absolute_position || DataModel::Bounds.zero
107
+
108
+ start_point = DataModel::Bounds.new(
109
+ x: source_bounds.left + source_bounds.width / 2.0,
110
+ y: source_bounds.top + source_bounds.height / 2.0,
111
+ width: 0,
112
+ height: 0
113
+ )
114
+ bp_bounds = connection.bendpoints.map do |bp|
115
+ DataModel::Bounds.new(
116
+ x: start_point.x + (bp.x || 0),
117
+ y: start_point.y + (bp.y || 0),
118
+ width: 0,
119
+ height: 0
120
+ )
121
+ end
122
+ bp_bounds = bp_bounds.reject do |bounds|
123
+ bounds.inside?(source_bounds) || bounds.inside?(target_bounds)
124
+ end
125
+
126
+ bounds = [source_bounds].concat(bp_bounds) << target_bounds
127
+
128
+ points = []
129
+ a = bounds.shift
130
+ until bounds.empty?
131
+ b = bounds.shift
132
+ points.concat(calc_points(a, b))
133
+ a = b
134
+ end
135
+ points.uniq!
136
+ [move_to(points.shift)].concat(points.map { |pt| line_to(pt) }).join(" ")
137
+ end
138
+
139
+ # a: Bounds
140
+ # b: Bounds
141
+ def calc_points(a, b)
142
+ ax_range = a.x_range
143
+ bx_range = b.x_range
144
+
145
+ overlap_x_center = ranges_overlap(ax_range, bx_range)
146
+
147
+ if overlap_x_center
148
+ ax = bx = overlap_x_center
149
+ elsif b.is_right_of?(a)
150
+ ax = a.right
151
+ bx = b.left
152
+ else
153
+ ax = a.left
154
+ bx = b.right
155
+ end
156
+
157
+ ay_range = a.y_range
158
+ by_range = b.y_range
159
+
160
+ overlap_y_center = ranges_overlap(ay_range, by_range)
161
+
162
+ if overlap_y_center
163
+ ay = by = overlap_y_center
164
+ elsif b.is_above?(a)
165
+ ay = a.top
166
+ by = b.bottom
167
+ else
168
+ ay = a.bottom
169
+ by = b.top
170
+ end
171
+
172
+ [Point.new(ax, ay), Point.new(bx, by)]
173
+ end
174
+
175
+ def move_to(point)
176
+ "M #{point.x} #{point.y}"
177
+ end
178
+
179
+ def line_to(point)
180
+ "L #{point.x} #{point.y}"
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ class CssStyle
6
+ attr_reader :style
7
+
8
+ def initialize(style)
9
+ @style = style
10
+ end
11
+
12
+ def text
13
+ return "" if style.nil?
14
+ to_css(
15
+ "fill": style.font_color&.to_rgba,
16
+ "color": style.font_color&.to_rgba,
17
+ "font-family": style.font&.name,
18
+ "font-size": style.font&.size,
19
+ "text-align": style.text_align
20
+ )
21
+ end
22
+
23
+ def to_css(style_hash)
24
+ style_hash
25
+ .delete_if { |_key, value| value.nil? }
26
+ .map { |key, value| "#{key}:#{value};" }
27
+ .join("")
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "nokogiri"
5
+
6
+ module Archimate
7
+ module Svg
8
+ class Diagram
9
+ attr_reader :diagram
10
+
11
+ def initialize(diagram)
12
+ @diagram = diagram
13
+ @svg_template = Nokogiri::XML(SvgTemplate.new.to_s).freeze
14
+ end
15
+
16
+ def to_svg
17
+ svg_doc = @svg_template.clone
18
+ set_title(svg_doc)
19
+ top_group = svg_doc.at_css("#archimate-diagram")
20
+ render_connections(
21
+ render_elements(top_group)
22
+ )
23
+ update_viewbox(svg_doc.at_css("svg"))
24
+ format_node(top_group)
25
+ svg_doc.to_xml(encoding: 'UTF-8', indent: 2)
26
+ end
27
+
28
+ def set_title(svg)
29
+ svg.at_css("title").content = diagram.name || "untitled"
30
+ svg.at_css("desc").content = diagram.documentation.first&.text || ""
31
+ end
32
+
33
+ # Scan the SVG and figure out min & max
34
+ def update_viewbox(svg)
35
+ extents = calculate_max_extents(svg).expand(10)
36
+ svg.set_attribute(:width, extents.width)
37
+ svg.set_attribute(:height, extents.height)
38
+ svg.set_attribute("viewBox", "#{extents.min_x} #{extents.min_y} #{extents.width} #{extents.height}")
39
+ svg
40
+ end
41
+
42
+ def format_node(node, depth = 4)
43
+ node.children.each do |child|
44
+ child.add_previous_sibling("\n#{ ' ' * depth }")
45
+ format_node(child, depth + 2)
46
+ child.add_next_sibling("\n#{ ' ' * (depth - 2) }") if node.children.last == child
47
+ end
48
+ end
49
+
50
+ def calculate_max_extents(doc)
51
+ node_vals =
52
+ doc
53
+ .xpath("//*[@x or @y]")
54
+ .map { |node| %w[x y width height].map { |attr| node.attr(attr).to_i } }
55
+ doc.css(".archimate-relationship")
56
+ .each { |path|
57
+ path.attr("d").split(" ").each_slice(3) do |point|
58
+ node_vals << [point[1].to_i, point[2].to_i, 0, 0]
59
+ end
60
+ }
61
+ Extents.new(
62
+ node_vals.map(&:first).min,
63
+ node_vals.map { |v| v[0] + v[2] }.max,
64
+ node_vals.map { |v| v[1] }.min,
65
+ node_vals.map { |v| v[1] + v[3] }.max
66
+ )
67
+ end
68
+
69
+ def attr_to_i(node, attr)
70
+ ival = node.attr(attr)
71
+ ival.to_i unless ival.nil? || ival.strip.empty?
72
+ end
73
+
74
+ def render_elements(svg_node)
75
+ diagram
76
+ .nodes
77
+ .reduce(svg_node) { |svg, child| Child.new(child).render_elements(svg) }
78
+ end
79
+
80
+ def render_connections(svg_node)
81
+ diagram
82
+ .connections
83
+ .reduce(svg_node) { |svg, connection| Connection.new(connection).render(svg) }
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ module Entity
6
+ class AndJunction < RectEntity
7
+ def initialize(child, bounds_offset)
8
+ super
9
+ @background_class = "archimate-junction-background"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ module Entity
6
+ class ApplicationCollaboration < RectEntity
7
+ def initialize(child, bounds_offset)
8
+ super
9
+ @badge = "#archimate-collaboration-badge"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ module Entity
6
+ # TODO: support alternate appearance
7
+ class ApplicationComponent < BaseEntity
8
+ def initialize(child, bounds_offset)
9
+ super
10
+ end
11
+
12
+ def entity_shape(xml, bounds)
13
+ component_path(xml, bounds)
14
+ end
15
+
16
+ def component_path(xml, bounds)
17
+ main_box_x = bounds.left + 21.0 / 2
18
+ main_box_width = bounds.width - 21 / 2
19
+ set_text_bounds(bounds, main_box_x)
20
+ xml.rect(x: main_box_x, y: bounds.top, width: main_box_width, height: bounds.height, class: background_class, style: shape_style)
21
+ component_decoration(xml, bounds.left, bounds.top + 10)
22
+ component_decoration(xml, bounds.left, bounds.top + 30)
23
+ end
24
+
25
+ def component_decoration(xml, left, top)
26
+ xml.rect(x: left, y: top, width: "21", height: "13", class: background_class, style: shape_style)
27
+ xml.rect(x: left, y: top, width: "21", height: "13", class: "archimate-decoration")
28
+ end
29
+
30
+ def set_text_bounds(bounds, main_box_x)
31
+ @text_bounds = DataModel::Bounds.new(
32
+ x: main_box_x + 21 / 2,
33
+ y: bounds.top + 1,
34
+ width: bounds.width - 22,
35
+ height: bounds.height - 2
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ module Entity
6
+ class ApplicationEvent < EventEntity
7
+ def initialize(child, bounds_offset)
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end