ea 0.6.96 → 0.6.97
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/config/themes/39.yml +8 -0
- data/lib/ea/sources/qea/diagram_builder/routing.rb +72 -0
- data/lib/ea/sources/qea/diagram_builder.rb +2 -1
- data/lib/ea/svg/ea_emitter/connector_redock.rb +15 -1
- data/lib/ea/svg/ea_emitter/label/end_label.rb +10 -0
- data/lib/ea/svg/ea_emitter/labels.rb +60 -6
- data/lib/ea/theme/definition.rb +23 -2
- data/lib/ea/theme/loader.rb +3 -1
- data/lib/ea/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c2ca3f0fd4381aec39af89849d601c85defa496b697f1fe625558c8a210aef64
|
|
4
|
+
data.tar.gz: adbc3773a202f06ad7327ace0fbea64daacea45a4719afb28959332673dafdcd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 99b878a17d58444e251964011cf2af59d46459223e657b8ffbf1a4602dc572af56e594bedd05c321cec0502d91e654cdd013d5b408277027d1c4f41c65885d3f
|
|
7
|
+
data.tar.gz: 73ef9107ec26ea7b60f7c9e5d00b7fa09b4d08b10842345c589a75dfd13a62b553287b95b0ad1b71e0c45fc032ab30ff1299fecb03e2a3abac69027a69180e97
|
|
@@ -8,6 +8,78 @@ module Ea
|
|
|
8
8
|
module Routing
|
|
9
9
|
private
|
|
10
10
|
|
|
11
|
+
# Stored SY/EY use mathematical Y; ray origins use screen Y.
|
|
12
|
+
# Computed-jog origins are already normalized to their derived ports.
|
|
13
|
+
def correct_stored_ray_origins(model, link_row, diagram_row, geom, context)
|
|
14
|
+
return model if context
|
|
15
|
+
return model unless stored_ray_candidate?(model, link_row, geom)
|
|
16
|
+
|
|
17
|
+
source, target = stored_ray_boxes(link_row, diagram_row)
|
|
18
|
+
return model unless stored_ray_gap?(source, target, model.style[:mode], geom[:edge])
|
|
19
|
+
|
|
20
|
+
set_stored_ray_origins(model, source, target, geom)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stored_ray_boxes(link_row, diagram_row)
|
|
24
|
+
connector = database.find_connector(link_row.connectorid)
|
|
25
|
+
[source_placement_for(connector, diagram_row),
|
|
26
|
+
target_placement_for(connector, diagram_row)].map { |placement| bounds_from_rect(placement) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def set_stored_ray_origins(model, source, target, geom)
|
|
30
|
+
model.source_anchor = stored_ray_origin(source, geom[:sx], geom[:sy])
|
|
31
|
+
model.target_anchor = stored_ray_origin(target, geom[:ex], geom[:ey])
|
|
32
|
+
model
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def stored_ray_candidate?(model, link_row, geom)
|
|
36
|
+
%w[Generalization Aggregation].include?(model.connector_type) &&
|
|
37
|
+
model.waypoints.size == 2 && stored_ray_style?(model.style, link_row) &&
|
|
38
|
+
stored_ray_geometry?(model, geom) && !normalized_port_anchors?(model)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def stored_ray_style?(style, link_row)
|
|
42
|
+
%w[1 3].include?(style[:mode]) && !style[:tree] &&
|
|
43
|
+
(style[:mode] == "1" || link_row.path.to_s.empty?)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def stored_ray_geometry?(model, geom)
|
|
47
|
+
model.has_geometry_offsets && model.source_port && model.target_port &&
|
|
48
|
+
(!geom[:sy].to_i.zero? || !geom[:ey].to_i.zero?)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def normalized_port_anchors?(model)
|
|
52
|
+
same_port_anchor?(model.source_anchor, model.source_port) &&
|
|
53
|
+
same_port_anchor?(model.target_anchor, model.target_port)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def same_port_anchor?(anchor, port)
|
|
57
|
+
anchor.x == port.x && anchor.y == port.y
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def stored_ray_gap?(source, target, mode, edge)
|
|
61
|
+
return horizontal_ray_gap?(source, target) || vertical_ray_gap?(source, target) if mode == "1"
|
|
62
|
+
|
|
63
|
+
if edge == 1
|
|
64
|
+
target.y + target.height < source.y
|
|
65
|
+
elsif edge == 4
|
|
66
|
+
target.x + target.width < source.x
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def horizontal_ray_gap?(source, target)
|
|
71
|
+
source.x + source.width < target.x || target.x + target.width < source.x
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def vertical_ray_gap?(source, target)
|
|
75
|
+
source.y + source.height < target.y || target.y + target.height < source.y
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def stored_ray_origin(bounds, x_offset, y_offset)
|
|
79
|
+
Ea::Model::Point.new(x: bounds.x + bounds.width / 2 + x_offset.to_i,
|
|
80
|
+
y: bounds.y + bounds.height / 2 - y_offset.to_i)
|
|
81
|
+
end
|
|
82
|
+
|
|
11
83
|
# Square routing keeps the stored orthogonal trunk, even when a
|
|
12
84
|
# shorter facing-edge route exists between the same boxes.
|
|
13
85
|
def stored_square_route(link_row, connector, source, target)
|
|
@@ -385,7 +385,7 @@ module Ea
|
|
|
385
385
|
geom = parse_geometry_fields(link_row.geometry)
|
|
386
386
|
context = ContextDiagramSupport.package_context(diagram_row) ||
|
|
387
387
|
ContextDiagramSupport.element_regenerate?(diagram_row)
|
|
388
|
-
collapse_computed_jog(Ea::Model::DiagramConnector.new(
|
|
388
|
+
model = collapse_computed_jog(Ea::Model::DiagramConnector.new(
|
|
389
389
|
id: IdNormalizer.synthetic("dc", diagram_row.diagram_id,
|
|
390
390
|
link_row.instance_id),
|
|
391
391
|
diagram_id: IdNormalizer.from_guid(diagram_row.ea_guid),
|
|
@@ -410,6 +410,7 @@ module Ea
|
|
|
410
410
|
has_geometry_offsets: geometry_has_offsets?(link_row.geometry),
|
|
411
411
|
is_substitutable: substitutable_connector?(connector)
|
|
412
412
|
), link_row, diagram_row, geom)
|
|
413
|
+
correct_stored_ray_origins(model, link_row, diagram_row, geom, context)
|
|
413
414
|
end
|
|
414
415
|
|
|
415
416
|
# Ray origin for one connector end: the element's center
|
|
@@ -106,7 +106,7 @@ module Ea
|
|
|
106
106
|
def outline_connector?(connector, bounds)
|
|
107
107
|
return true if %w[Generalization Aggregation].include?(connector.connector_type)
|
|
108
108
|
|
|
109
|
-
return false unless stored_association?(connector)
|
|
109
|
+
return false unless stored_association?(connector) || offset_free_association?(connector)
|
|
110
110
|
|
|
111
111
|
# Diagonal Association rounding and tree docks keep their existing rules.
|
|
112
112
|
pairs = clipped_pairs(bounds, [connector.source_anchor, connector.target_anchor])
|
|
@@ -122,6 +122,20 @@ module Ea
|
|
|
122
122
|
end
|
|
123
123
|
private_class_method :stored_association?
|
|
124
124
|
|
|
125
|
+
def offset_free_association?(connector)
|
|
126
|
+
style = connector.style.to_h
|
|
127
|
+
connector.connector_type == "Association" && style[:mode] == "3" && !style[:tree] &&
|
|
128
|
+
%i[direct regenerated].none? { |key| style.key?(key) } && offset_free_anchors?(connector)
|
|
129
|
+
end
|
|
130
|
+
private_class_method :offset_free_association?
|
|
131
|
+
|
|
132
|
+
def offset_free_anchors?(connector)
|
|
133
|
+
!connector.has_geometry_offsets &&
|
|
134
|
+
[connector.source_port, connector.target_port].all?(&:nil?) &&
|
|
135
|
+
[connector.source_anchor, connector.target_anchor].all?
|
|
136
|
+
end
|
|
137
|
+
private_class_method :offset_free_anchors?
|
|
138
|
+
|
|
125
139
|
def clipped_pairs(bounds, anchors)
|
|
126
140
|
source, target = bounds
|
|
127
141
|
source_anchor, target_anchor = anchors
|
|
@@ -91,6 +91,8 @@ module Ea
|
|
|
91
91
|
role_seat(direction, anchor, text_box, role) || text_pos
|
|
92
92
|
mult_pos = directional_multiplicity(connector, direction, anchor, mult_box, mult) ||
|
|
93
93
|
mult_seat(direction, anchor, mult_box) || mult_pos
|
|
94
|
+
elsif end_kind == :target && !(tree && zero_offset?(text_box, mult_box))
|
|
95
|
+
mult_pos = target_multiplicity_seat(heading, anchor, mult_box) || mult_pos
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
build_texts(role:, mult:, standalone:,
|
|
@@ -251,6 +253,14 @@ module Ea
|
|
|
251
253
|
[x - width - 3, y + 15] if width
|
|
252
254
|
end
|
|
253
255
|
|
|
256
|
+
def target_multiplicity_seat(heading, anchor, box)
|
|
257
|
+
return nil unless seat_font?
|
|
258
|
+
return nil unless heading && heading[0].zero? && heading[1].negative?
|
|
259
|
+
return nil unless cambria_box?(box) && stored_offsets_zero?(box)
|
|
260
|
+
|
|
261
|
+
[anchor[0] + 8, anchor[1] - 7]
|
|
262
|
+
end
|
|
263
|
+
|
|
254
264
|
def cambria_box?(box)
|
|
255
265
|
box && default_presentation?(box) && font_family.to_s.casecmp("Cambria").zero?
|
|
256
266
|
end
|
|
@@ -97,6 +97,7 @@ module Ea
|
|
|
97
97
|
mult_box: tgt_mb,
|
|
98
98
|
anchor: target_pt, connector: connector,
|
|
99
99
|
end_kind: :target, tree: tree && tree[:target],
|
|
100
|
+
heading: stored_tgt && leg_heading(points.reverse),
|
|
100
101
|
stored_labels: stored_labels).each { |t| texts << t }
|
|
101
102
|
texts
|
|
102
103
|
end
|
|
@@ -112,11 +113,21 @@ module Ea
|
|
|
112
113
|
{ source: true, target: true }
|
|
113
114
|
end
|
|
114
115
|
|
|
115
|
-
#
|
|
116
|
-
#
|
|
116
|
+
# A diagonal clipped leg keeps the seat of its unambiguous exit face.
|
|
117
|
+
# Unknown faces retain the stored-upward fallback.
|
|
117
118
|
def source_heading(connector, points)
|
|
118
119
|
heading = leg_heading(points)
|
|
119
|
-
return heading unless points.size == 2 && heading
|
|
120
|
+
return heading unless points.size == 2 && heading.none?(&:zero?)
|
|
121
|
+
|
|
122
|
+
box = source_dock_bounds(connector)
|
|
123
|
+
face = box && dock_face_heading(points.first, box)
|
|
124
|
+
return face if face && face.zip(heading).any? { |axis, delta| (axis * delta).positive? }
|
|
125
|
+
|
|
126
|
+
stored_upward_heading(connector, heading)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def stored_upward_heading(connector, heading)
|
|
130
|
+
return heading unless heading[1].negative?
|
|
120
131
|
|
|
121
132
|
stored = waypoint_pairs(connector)
|
|
122
133
|
return heading unless stored.size == 2
|
|
@@ -125,6 +136,49 @@ module Ea
|
|
|
125
136
|
original[0].zero? && original[1].negative? ? original : heading
|
|
126
137
|
end
|
|
127
138
|
|
|
139
|
+
def source_dock_bounds(connector)
|
|
140
|
+
return nil unless model_index && drawn_bounds
|
|
141
|
+
|
|
142
|
+
relationship = model_index[connector.relationship_ref]
|
|
143
|
+
return nil unless relationship
|
|
144
|
+
|
|
145
|
+
source, target = ConnectorRedock.end_refs(relationship)
|
|
146
|
+
return nil if source == target
|
|
147
|
+
return nil unless drawn_bounds[target]
|
|
148
|
+
|
|
149
|
+
drawn_bounds[source]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def dock_face_heading(point, box)
|
|
153
|
+
return nil unless box.width.positive? && box.height.positive?
|
|
154
|
+
|
|
155
|
+
vertical_dock_heading(point, box) || horizontal_dock_heading(point, box)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def vertical_dock_heading(point, box)
|
|
159
|
+
x, y = point
|
|
160
|
+
left = box.x
|
|
161
|
+
return nil unless x > left && x < left + box.width
|
|
162
|
+
|
|
163
|
+
top = box.y
|
|
164
|
+
return [0, -1] if [top, top - 1].include?(y)
|
|
165
|
+
|
|
166
|
+
bottom = top + box.height
|
|
167
|
+
[0, 1] if [bottom, bottom + 1].include?(y)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def horizontal_dock_heading(point, box)
|
|
171
|
+
x, y = point
|
|
172
|
+
top = box.y
|
|
173
|
+
return nil unless y > top && y < top + box.height
|
|
174
|
+
|
|
175
|
+
left = box.x
|
|
176
|
+
return [-1, 0] if [left, left - 1].include?(x)
|
|
177
|
+
|
|
178
|
+
right = left + box.width
|
|
179
|
+
[1, 0] if [right, right + 1].include?(x)
|
|
180
|
+
end
|
|
181
|
+
|
|
128
182
|
def leg_heading(points)
|
|
129
183
|
[points[1][0] - points[0][0], points[1][1] - points[0][1]]
|
|
130
184
|
end
|
|
@@ -172,7 +226,7 @@ module Ea
|
|
|
172
226
|
theme: theme,
|
|
173
227
|
font_family: label_font_family,
|
|
174
228
|
font_size: label_font_size,
|
|
175
|
-
font_unit: theme.
|
|
229
|
+
font_unit: theme.label_font_size_unit
|
|
176
230
|
)
|
|
177
231
|
end
|
|
178
232
|
|
|
@@ -182,7 +236,7 @@ module Ea
|
|
|
182
236
|
model_index: model_index,
|
|
183
237
|
font_family: label_font_family,
|
|
184
238
|
font_size: label_font_size,
|
|
185
|
-
font_unit: theme.
|
|
239
|
+
font_unit: theme.label_font_size_unit
|
|
186
240
|
)
|
|
187
241
|
end
|
|
188
242
|
|
|
@@ -212,7 +266,7 @@ module Ea
|
|
|
212
266
|
end
|
|
213
267
|
|
|
214
268
|
def label_font_size
|
|
215
|
-
theme.
|
|
269
|
+
theme.label_font_size || DEFAULT_SIZE
|
|
216
270
|
end
|
|
217
271
|
end
|
|
218
272
|
end
|
data/lib/ea/theme/definition.rb
CHANGED
|
@@ -65,7 +65,8 @@ module Ea
|
|
|
65
65
|
text_y_offset: 12, line_height: 13).freeze
|
|
66
66
|
|
|
67
67
|
def initialize(id:, name: nil, font_family: nil, font_size: nil,
|
|
68
|
-
label_font_family: nil,
|
|
68
|
+
label_font_family: nil, label_font_size: nil,
|
|
69
|
+
label_font_size_unit: nil,
|
|
69
70
|
font_size_unit: "pt", text_weight_normal: 400,
|
|
70
71
|
text_weight_bold: 700,
|
|
71
72
|
element_font_size: 9, element_font_unit: "pt",
|
|
@@ -83,6 +84,8 @@ module Ea
|
|
|
83
84
|
@name = name
|
|
84
85
|
@font_family = font_family
|
|
85
86
|
@label_font_family = label_font_family
|
|
87
|
+
@label_font_size = label_font_size
|
|
88
|
+
@label_font_size_unit = label_font_size_unit
|
|
86
89
|
@font_size = font_size
|
|
87
90
|
@font_size_unit = font_size_unit
|
|
88
91
|
@text_weight_normal = text_weight_normal
|
|
@@ -125,8 +128,18 @@ module Ea
|
|
|
125
128
|
@label_font_family || font_family
|
|
126
129
|
end
|
|
127
130
|
|
|
131
|
+
def label_font_size
|
|
132
|
+
@label_font_size || font_size
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def label_font_size_unit
|
|
136
|
+
@label_font_size_unit || font_size_unit
|
|
137
|
+
end
|
|
138
|
+
|
|
128
139
|
def with(**overrides)
|
|
129
|
-
overrides
|
|
140
|
+
clear_label_override(overrides, :font_family, :label_font_family)
|
|
141
|
+
clear_label_override(overrides, :font_size, :label_font_size)
|
|
142
|
+
clear_label_override(overrides, :font_size_unit, :label_font_size_unit)
|
|
130
143
|
Definition.new(**to_h.merge(overrides))
|
|
131
144
|
end
|
|
132
145
|
|
|
@@ -159,6 +172,8 @@ module Ea
|
|
|
159
172
|
font_family: font_family, font_size: font_size,
|
|
160
173
|
font_size_unit: font_size_unit,
|
|
161
174
|
label_font_family: @label_font_family,
|
|
175
|
+
label_font_size: @label_font_size,
|
|
176
|
+
label_font_size_unit: @label_font_size_unit,
|
|
162
177
|
text_weight_normal: text_weight_normal,
|
|
163
178
|
text_weight_bold: text_weight_bold,
|
|
164
179
|
element_font_size: element_font_size,
|
|
@@ -179,6 +194,12 @@ module Ea
|
|
|
179
194
|
package: package, note: note, fills: fills
|
|
180
195
|
}
|
|
181
196
|
end
|
|
197
|
+
|
|
198
|
+
private
|
|
199
|
+
|
|
200
|
+
def clear_label_override(overrides, global_key, label_key)
|
|
201
|
+
overrides[label_key] = nil if overrides.key?(global_key) && !overrides.key?(label_key)
|
|
202
|
+
end
|
|
182
203
|
end
|
|
183
204
|
end
|
|
184
205
|
end
|
data/lib/ea/theme/loader.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Ea
|
|
|
10
10
|
# name: EA White Theme
|
|
11
11
|
# font: { family: Carlito, size: 7, unit: pt, weight_normal: 400, ... }
|
|
12
12
|
# element_font: { size: 9, unit: pt }
|
|
13
|
-
# label_font: { family: Cambria }
|
|
13
|
+
# label_font: { family: Cambria, size: 7, unit: pt }
|
|
14
14
|
# colors: { text: "#000000", attribute_text: "#66413F", ... }
|
|
15
15
|
# strokes: { element_border: 2, connector_line: 2, ... }
|
|
16
16
|
# text_metrics: { width_factor: 0.65 }
|
|
@@ -56,6 +56,8 @@ module Ea
|
|
|
56
56
|
name: data["name"],
|
|
57
57
|
font_family: font["family"],
|
|
58
58
|
label_font_family: label_font["family"],
|
|
59
|
+
label_font_size: label_font["size"],
|
|
60
|
+
label_font_size_unit: label_font["unit"],
|
|
59
61
|
font_size: font["size"],
|
|
60
62
|
font_size_unit: font["unit"] || "pt",
|
|
61
63
|
text_weight_normal: font["weight_normal"] || 400,
|
data/lib/ea/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ea
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.97
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -501,6 +501,7 @@ files:
|
|
|
501
501
|
- config/qea_schema.yml
|
|
502
502
|
- config/stereotype_colors.yml
|
|
503
503
|
- config/themes/119.yml
|
|
504
|
+
- config/themes/39.yml
|
|
504
505
|
- config/themes/default.yml
|
|
505
506
|
- docs/ea_to_uml_type_mapping.md
|
|
506
507
|
- docs/xmi_qea_conversion_capabilities.md
|