archimate 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.projectile +18 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +4 -0
- data/.yardocs +15 -0
- data/Gemfile +5 -0
- data/Guardfile +27 -0
- data/LICENSE +201 -0
- data/README.md +94 -0
- data/Rakefile +29 -0
- data/TODOs.org +286 -0
- data/archimate.gemspec +51 -0
- data/bin/archimate +17 -0
- data/bin/console +13 -0
- data/bin/setup +8 -0
- data/exe/archidiff +7 -0
- data/exe/archidiff-summary +7 -0
- data/exe/archimate +7 -0
- data/exe/archimerge +7 -0
- data/exe/fmtxml +7 -0
- data/lib/archimate/cli/archi.rb +189 -0
- data/lib/archimate/cli/cleanup.rb +54 -0
- data/lib/archimate/cli/conflict_resolver.rb +39 -0
- data/lib/archimate/cli/convert.rb +39 -0
- data/lib/archimate/cli/diff.rb +31 -0
- data/lib/archimate/cli/diff_summary.rb +101 -0
- data/lib/archimate/cli/duper.rb +85 -0
- data/lib/archimate/cli/lint.rb +16 -0
- data/lib/archimate/cli/mapper.rb +82 -0
- data/lib/archimate/cli/merge.rb +49 -0
- data/lib/archimate/cli/merger.rb +109 -0
- data/lib/archimate/cli/stats.rb +42 -0
- data/lib/archimate/cli/svger.rb +40 -0
- data/lib/archimate/color.rb +53 -0
- data/lib/archimate/config.rb +35 -0
- data/lib/archimate/data_model/any_attribute.rb +13 -0
- data/lib/archimate/data_model/any_element.rb +15 -0
- data/lib/archimate/data_model/archimate_node.rb +181 -0
- data/lib/archimate/data_model/bounds.rb +72 -0
- data/lib/archimate/data_model/color.rb +47 -0
- data/lib/archimate/data_model/concept.rb +14 -0
- data/lib/archimate/data_model/concern.rb +17 -0
- data/lib/archimate/data_model/connection.rb +107 -0
- data/lib/archimate/data_model/constants.rb +82 -0
- data/lib/archimate/data_model/container.rb +17 -0
- data/lib/archimate/data_model/diagram.rb +40 -0
- data/lib/archimate/data_model/diffable_array.rb +213 -0
- data/lib/archimate/data_model/diffable_primitive.rb +83 -0
- data/lib/archimate/data_model/documentation.rb +14 -0
- data/lib/archimate/data_model/element.rb +87 -0
- data/lib/archimate/data_model/font.rb +54 -0
- data/lib/archimate/data_model/label.rb +19 -0
- data/lib/archimate/data_model/lang_string.rb +41 -0
- data/lib/archimate/data_model/location.rb +31 -0
- data/lib/archimate/data_model/metadata.rb +14 -0
- data/lib/archimate/data_model/model.rb +217 -0
- data/lib/archimate/data_model/modeling_note.rb +13 -0
- data/lib/archimate/data_model/named_referenceable.rb +14 -0
- data/lib/archimate/data_model/organization.rb +40 -0
- data/lib/archimate/data_model/property.rb +25 -0
- data/lib/archimate/data_model/property_definition.rb +16 -0
- data/lib/archimate/data_model/referenceable.rb +29 -0
- data/lib/archimate/data_model/relationship.rb +85 -0
- data/lib/archimate/data_model/schema_info.rb +18 -0
- data/lib/archimate/data_model/style.rb +32 -0
- data/lib/archimate/data_model/view.rb +12 -0
- data/lib/archimate/data_model/view_concept.rb +18 -0
- data/lib/archimate/data_model/view_node.rb +114 -0
- data/lib/archimate/data_model/viewpoint.rb +87 -0
- data/lib/archimate/data_model.rb +54 -0
- data/lib/archimate/diff/archimate_array_reference.rb +113 -0
- data/lib/archimate/diff/archimate_identified_node_reference.rb +41 -0
- data/lib/archimate/diff/archimate_node_attribute_reference.rb +70 -0
- data/lib/archimate/diff/archimate_node_reference.rb +80 -0
- data/lib/archimate/diff/change.rb +49 -0
- data/lib/archimate/diff/conflict.rb +31 -0
- data/lib/archimate/diff/conflicts/base_conflict.rb +53 -0
- data/lib/archimate/diff/conflicts/deleted_items_child_updated_conflict.rb +30 -0
- data/lib/archimate/diff/conflicts/deleted_items_referenced_conflict.rb +63 -0
- data/lib/archimate/diff/conflicts/path_conflict.rb +51 -0
- data/lib/archimate/diff/conflicts.rb +89 -0
- data/lib/archimate/diff/delete.rb +41 -0
- data/lib/archimate/diff/difference.rb +113 -0
- data/lib/archimate/diff/insert.rb +43 -0
- data/lib/archimate/diff/merge.rb +70 -0
- data/lib/archimate/diff/move.rb +51 -0
- data/lib/archimate/diff.rb +17 -0
- data/lib/archimate/export/csv_export.rb +32 -0
- data/lib/archimate/export/cypher.rb +171 -0
- data/lib/archimate/export/graph_ml.rb +131 -0
- data/lib/archimate/export/n_quads.rb +142 -0
- data/lib/archimate/file_format.rb +30 -0
- data/lib/archimate/file_formats/archi_file_format.rb +151 -0
- data/lib/archimate/file_formats/archi_file_reader.rb +252 -0
- data/lib/archimate/file_formats/archi_file_writer.rb +230 -0
- data/lib/archimate/file_formats/archimate_v2.rb +461 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_lang_string.rb +35 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_metadata.rb +115 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_property_definitions.rb +28 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_property_defs.rb +27 -0
- data/lib/archimate/file_formats/model_exchange_file_reader.rb +237 -0
- data/lib/archimate/file_formats/model_exchange_file_reader_21.rb +73 -0
- data/lib/archimate/file_formats/model_exchange_file_reader_30.rb +134 -0
- data/lib/archimate/file_formats/model_exchange_file_writer.rb +157 -0
- data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +143 -0
- data/lib/archimate/file_formats/model_exchange_file_writer_30.rb +153 -0
- data/lib/archimate/file_formats/writer.rb +56 -0
- data/lib/archimate/lint/duplicate_entities.rb +121 -0
- data/lib/archimate/lint/linter.rb +146 -0
- data/lib/archimate/logging.rb +55 -0
- data/lib/archimate/maybe_io.rb +34 -0
- data/lib/archimate/progress_indicator.rb +29 -0
- data/lib/archimate/svg/archimate.css +232 -0
- data/lib/archimate/svg/child.rb +29 -0
- data/lib/archimate/svg/connection.rb +184 -0
- data/lib/archimate/svg/css_style.rb +31 -0
- data/lib/archimate/svg/diagram.rb +87 -0
- data/lib/archimate/svg/entity/and_junction.rb +14 -0
- data/lib/archimate/svg/entity/application_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/application_component.rb +41 -0
- data/lib/archimate/svg/entity/application_event.rb +13 -0
- data/lib/archimate/svg/entity/application_function.rb +13 -0
- data/lib/archimate/svg/entity/application_interaction.rb +13 -0
- data/lib/archimate/svg/entity/application_interface.rb +13 -0
- data/lib/archimate/svg/entity/application_process.rb +13 -0
- data/lib/archimate/svg/entity/application_service.rb +13 -0
- data/lib/archimate/svg/entity/artifact.rb +39 -0
- data/lib/archimate/svg/entity/assessment.rb +14 -0
- data/lib/archimate/svg/entity/base_entity.rb +128 -0
- data/lib/archimate/svg/entity/business_actor.rb +14 -0
- data/lib/archimate/svg/entity/business_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/business_event.rb +10 -0
- data/lib/archimate/svg/entity/business_function.rb +13 -0
- data/lib/archimate/svg/entity/business_interaction.rb +13 -0
- data/lib/archimate/svg/entity/business_interface.rb +13 -0
- data/lib/archimate/svg/entity/business_object.rb +13 -0
- data/lib/archimate/svg/entity/business_process.rb +13 -0
- data/lib/archimate/svg/entity/business_role.rb +14 -0
- data/lib/archimate/svg/entity/business_service.rb +13 -0
- data/lib/archimate/svg/entity/capability.rb +14 -0
- data/lib/archimate/svg/entity/communication_network.rb +14 -0
- data/lib/archimate/svg/entity/communication_path.rb +14 -0
- data/lib/archimate/svg/entity/constraint.rb +15 -0
- data/lib/archimate/svg/entity/contract.rb +13 -0
- data/lib/archimate/svg/entity/course_of_action.rb +14 -0
- data/lib/archimate/svg/entity/data_entity.rb +29 -0
- data/lib/archimate/svg/entity/data_object.rb +13 -0
- data/lib/archimate/svg/entity/deliverable.rb +13 -0
- data/lib/archimate/svg/entity/device.rb +48 -0
- data/lib/archimate/svg/entity/diagram_model_reference.rb +22 -0
- data/lib/archimate/svg/entity/diagram_object.rb +30 -0
- data/lib/archimate/svg/entity/distribution_network.rb +14 -0
- data/lib/archimate/svg/entity/driver.rb +14 -0
- data/lib/archimate/svg/entity/equipment.rb +16 -0
- data/lib/archimate/svg/entity/event_entity.rb +36 -0
- data/lib/archimate/svg/entity/facility.rb +16 -0
- data/lib/archimate/svg/entity/function_entity.rb +14 -0
- data/lib/archimate/svg/entity/gap.rb +21 -0
- data/lib/archimate/svg/entity/goal.rb +14 -0
- data/lib/archimate/svg/entity/group.rb +24 -0
- data/lib/archimate/svg/entity/implementation_event.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_function.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_interface.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_service.rb +13 -0
- data/lib/archimate/svg/entity/interaction_entity.rb +14 -0
- data/lib/archimate/svg/entity/interface_entity.rb +35 -0
- data/lib/archimate/svg/entity/junction.rb +19 -0
- data/lib/archimate/svg/entity/location.rb +14 -0
- data/lib/archimate/svg/entity/material.rb +14 -0
- data/lib/archimate/svg/entity/meaning.rb +40 -0
- data/lib/archimate/svg/entity/motivation_entity.rb +40 -0
- data/lib/archimate/svg/entity/network.rb +14 -0
- data/lib/archimate/svg/entity/node.rb +33 -0
- data/lib/archimate/svg/entity/node_shape.rb +64 -0
- data/lib/archimate/svg/entity/note.rb +30 -0
- data/lib/archimate/svg/entity/or_junction.rb +14 -0
- data/lib/archimate/svg/entity/outcome.rb +15 -0
- data/lib/archimate/svg/entity/path.rb +14 -0
- data/lib/archimate/svg/entity/plateau.rb +15 -0
- data/lib/archimate/svg/entity/principle.rb +15 -0
- data/lib/archimate/svg/entity/process_entity.rb +63 -0
- data/lib/archimate/svg/entity/product.rb +20 -0
- data/lib/archimate/svg/entity/rect.rb +13 -0
- data/lib/archimate/svg/entity/rect_entity.rb +25 -0
- data/lib/archimate/svg/entity/representation.rb +31 -0
- data/lib/archimate/svg/entity/requirement.rb +15 -0
- data/lib/archimate/svg/entity/resource.rb +14 -0
- data/lib/archimate/svg/entity/rounded_rect_entity.rb +23 -0
- data/lib/archimate/svg/entity/service_entity.rb +51 -0
- data/lib/archimate/svg/entity/sketch_model_sticky.rb +14 -0
- data/lib/archimate/svg/entity/stakeholder.rb +15 -0
- data/lib/archimate/svg/entity/system_software.rb +14 -0
- data/lib/archimate/svg/entity/technology_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/technology_event.rb +13 -0
- data/lib/archimate/svg/entity/technology_function.rb +13 -0
- data/lib/archimate/svg/entity/technology_interaction.rb +13 -0
- data/lib/archimate/svg/entity/technology_interface.rb +13 -0
- data/lib/archimate/svg/entity/technology_process.rb +13 -0
- data/lib/archimate/svg/entity/technology_service.rb +13 -0
- data/lib/archimate/svg/entity/value.rb +27 -0
- data/lib/archimate/svg/entity/work_package.rb +14 -0
- data/lib/archimate/svg/entity.rb +93 -0
- data/lib/archimate/svg/entity_factory.rb +17 -0
- data/lib/archimate/svg/extents.rb +27 -0
- data/lib/archimate/svg/point.rb +7 -0
- data/lib/archimate/svg/svg_template.rb +27 -0
- data/lib/archimate/svg/svg_template.svg.erb +169 -0
- data/lib/archimate/version.rb +4 -0
- data/lib/archimate.rb +114 -0
- 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,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
|