ea 0.6.112 → 0.6.113
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/lib/ea/svg/ea_emitter/label/end_label.rb +87 -6
- data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +18 -4
- data/lib/ea/svg/ea_emitter/labels.rb +13 -1
- data/lib/ea/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 673f03cddf9ae4a7cb297beaa9b9fab0b3e272e26771d976c90c521726465af5
|
|
4
|
+
data.tar.gz: 1147cce73671336e59d68dc04caeee0cb66276ce946e5af3a8b07d378f21ac7b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 44fcd7c27d72d01fef2fdf70498bee178904e54af09484506ff61ff2372281cbc03b5c7d23d4750f4ad7f1c2a474ad3fb3c79cfbbcc61e520f151d11a670a2be
|
|
7
|
+
data.tar.gz: 5a5ba8607a019d59be72fa1416cfbd66056e751420318bc02042a0ba02bd82dcc66452a97d25c26b2a0f408f132a2891a37db3e19f14f1c4ad98dfe1f4319c19
|
|
@@ -100,12 +100,18 @@ module Ea
|
|
|
100
100
|
mult_seat(direction, anchor, mult_box) || mult_pos
|
|
101
101
|
elsif end_kind == :target && !(tree && zero_offset?(text_box, mult_box))
|
|
102
102
|
text_pos = target_property_role(connector, heading, anchor, text_box, role) ||
|
|
103
|
+
target_diagonal_property_role(connector, heading, anchor, text_box, role) ||
|
|
103
104
|
target_vertical_role(connector, heading, anchor, text_box, role) ||
|
|
104
105
|
target_rightward_role(heading, anchor, text_box, role) || text_pos
|
|
105
106
|
mult_pos = target_multiplicity_seat(connector, heading, anchor, mult_box) ||
|
|
106
107
|
target_horizontal_multiplicity(heading, anchor, mult_box, mult) || mult_pos
|
|
107
108
|
end
|
|
108
109
|
|
|
110
|
+
if end_kind == :source
|
|
111
|
+
text_pos = source_top_property_role(connector, heading, anchor, text_box, role) ||
|
|
112
|
+
source_bottom_property_role(connector, heading, anchor, text_box, role) || text_pos
|
|
113
|
+
end
|
|
114
|
+
|
|
109
115
|
build_texts(role:, mult:, standalone:,
|
|
110
116
|
text_pos:, mult_pos:, stereo:, text_box:)
|
|
111
117
|
end
|
|
@@ -185,10 +191,10 @@ module Ea
|
|
|
185
191
|
[x + SEAT_X_INSET, y - 7]
|
|
186
192
|
end
|
|
187
193
|
|
|
188
|
-
# Property-role clusters use a direction-specific
|
|
194
|
+
# Property-role clusters use a direction-specific horizontal seat;
|
|
189
195
|
# alignment controls the stereotype line within that cluster.
|
|
190
196
|
def source_property_seat(connector, direction, anchor, box, role)
|
|
191
|
-
return nil unless %i[up left down].include?(direction) && property_role_box?(box, direction)
|
|
197
|
+
return nil unless %i[up left right down].include?(direction) && property_role_box?(box, direction)
|
|
192
198
|
return nil unless source_property_font?(connector, direction)
|
|
193
199
|
|
|
194
200
|
width = Ea::Fonts::Metrics.text_length(role, font_size, family: font_family)
|
|
@@ -196,11 +202,59 @@ module Ea
|
|
|
196
202
|
|
|
197
203
|
x, y = seat_corner(anchor, box)
|
|
198
204
|
inset, baseline = property_role_offsets(direction)
|
|
199
|
-
left = x
|
|
205
|
+
left = property_role_x(direction, x, inset + width)
|
|
200
206
|
left = [left, MIN_ROLE_X].max if direction == :up
|
|
201
207
|
[left, y + baseline]
|
|
202
208
|
end
|
|
203
209
|
|
|
210
|
+
def property_role_x(direction, origin, offset)
|
|
211
|
+
direction == :right ? origin + offset : origin - offset
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# EDGE=1 certifies the top dock independently of the clipped ray's
|
|
215
|
+
# heading. An absent source box uses the upward Property seat.
|
|
216
|
+
def source_top_property_role(connector, heading, anchor, box, role)
|
|
217
|
+
return nil unless source_seat?(:source, heading) && heading[0].negative? && heading[1].positive?
|
|
218
|
+
return nil unless zero_source_property_box?(box)
|
|
219
|
+
|
|
220
|
+
return nil unless source_top_property_route?(connector.style.to_h)
|
|
221
|
+
|
|
222
|
+
source_property_seat(connector, :up, anchor, box, role)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def zero_source_property_box?(box)
|
|
226
|
+
box && box["alignment"]&.zero? && stored_offsets_zero?(box)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def source_top_property_route?(style)
|
|
230
|
+
style[:stored_top_dock] == true && style.values_at(:mode, :lwidth, :tree) == ["3", "2", nil]
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# A saved external ray that first meets the source's bottom face
|
|
234
|
+
# seats an absent source Property role like the downward Property
|
|
235
|
+
# seat. The caller reports that face as a downward heading.
|
|
236
|
+
def source_bottom_property_role(connector, heading, anchor, box, role)
|
|
237
|
+
return nil unless source_bottom_dock?(connector, heading, box)
|
|
238
|
+
|
|
239
|
+
width = Ea::Fonts::Metrics.text_length(role, font_size, family: font_family)
|
|
240
|
+
return nil unless width
|
|
241
|
+
|
|
242
|
+
x, y = seat_corner(anchor, box)
|
|
243
|
+
inset, baseline = property_role_offsets(:down)
|
|
244
|
+
[x - inset - width, y + baseline]
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def source_bottom_dock?(connector, heading, box)
|
|
248
|
+
source_seat?(:source, heading) && heading[0].zero? && heading[1].positive? &&
|
|
249
|
+
zero_source_property_box?(box) && default_presentation?(box) &&
|
|
250
|
+
source_bottom_property_route?(connector.style.to_h) &&
|
|
251
|
+
source_property_font?(connector, :down)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def source_bottom_property_route?(style)
|
|
255
|
+
style[:stored_association_ray] == true && style.values_at(:mode, :lwidth, :tree) == ["3", "2", nil]
|
|
256
|
+
end
|
|
257
|
+
|
|
204
258
|
def plain_upward_seat(connector, direction, anchor, box, role)
|
|
205
259
|
return nil unless direction == :up && cambria_box?(box)
|
|
206
260
|
return nil unless [0, 1].include?(box["alignment"])
|
|
@@ -233,6 +287,31 @@ module Ea
|
|
|
233
287
|
property_label?(connector, :target) && downward_property_route?(connector.style.to_h)
|
|
234
288
|
end
|
|
235
289
|
|
|
290
|
+
# Zero-offset diagonal labels use the dominant leg's Property
|
|
291
|
+
# right edge. Moved boxes keep their explicit placement.
|
|
292
|
+
def target_diagonal_property_role(connector, heading, anchor, box, role)
|
|
293
|
+
return nil unless diagonal_property_box?(connector, box)
|
|
294
|
+
|
|
295
|
+
inset = diagonal_property_inset(heading)
|
|
296
|
+
width = Ea::Fonts::Metrics.text_length(role, font_size, family: font_family) if inset
|
|
297
|
+
[anchor[0] - inset - width, anchor[1] - 7] if width
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def diagonal_property_box?(connector, box)
|
|
301
|
+
plain_vertical_box?(box) && box["alignment"] == 1 && stored_offsets_zero?(box) &&
|
|
302
|
+
property_label?(connector, :target) &&
|
|
303
|
+
connector.style.to_h.values_at(:mode, :lwidth, :tree) == ["3", "0", nil]
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def diagonal_property_inset(heading)
|
|
307
|
+
return nil unless heading && !heading.include?(0)
|
|
308
|
+
|
|
309
|
+
dx, dy = heading
|
|
310
|
+
return property_role_offsets(:left).first if dx.negative? && dx.abs > dy.abs
|
|
311
|
+
|
|
312
|
+
property_role_offsets(:down).first if dy.negative? && dy.abs > dx.abs
|
|
313
|
+
end
|
|
314
|
+
|
|
236
315
|
def target_vertical_role(connector, heading, anchor, box, role)
|
|
237
316
|
return nil unless heading && heading[0].zero? && !heading[1].zero?
|
|
238
317
|
|
|
@@ -301,7 +380,7 @@ module Ea
|
|
|
301
380
|
def property_role_offsets(direction)
|
|
302
381
|
case direction
|
|
303
382
|
when :up then [60, -6]
|
|
304
|
-
when :left then [60, -7]
|
|
383
|
+
when :left, :right then [60, -7]
|
|
305
384
|
else [65, 15]
|
|
306
385
|
end
|
|
307
386
|
end
|
|
@@ -315,14 +394,16 @@ module Ea
|
|
|
315
394
|
def source_property_route?(style, direction)
|
|
316
395
|
case direction
|
|
317
396
|
when :left then left_property_route?(style)
|
|
397
|
+
when :right then style.values_at(:mode, :lwidth, :tree) == %w[3 2 H]
|
|
318
398
|
when :down then downward_property_route?(style)
|
|
319
399
|
else %w[0 2].include?(style[:lwidth]) && style[:tree] != "OS"
|
|
320
400
|
end
|
|
321
401
|
end
|
|
322
402
|
|
|
323
403
|
def left_property_route?(style)
|
|
324
|
-
|
|
325
|
-
[
|
|
404
|
+
downward_property_route?(style) ||
|
|
405
|
+
(style[:mode] == "3" && %w[0 2].include?(style[:lwidth]) &&
|
|
406
|
+
[nil, "H", "LV"].include?(style[:tree]))
|
|
326
407
|
end
|
|
327
408
|
|
|
328
409
|
def downward_property_route?(style)
|
|
@@ -96,8 +96,8 @@ module Ea
|
|
|
96
96
|
LINE_PITCH = 13
|
|
97
97
|
|
|
98
98
|
def label_position(connector, points)
|
|
99
|
-
|
|
100
|
-
return
|
|
99
|
+
stored_seat = stored_stereotype_position(connector, points) || stored_name_position(connector, points)
|
|
100
|
+
return stored_seat if stored_seat
|
|
101
101
|
|
|
102
102
|
return midpoint(points) unless default_substitutable_seat?(connector) &&
|
|
103
103
|
upward_four_point_route?(points)
|
|
@@ -106,9 +106,23 @@ module Ea
|
|
|
106
106
|
[source[0] + 3, ((source[1] + bend[1]) / 2).floor - 1]
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
+
# LMB is the row below the midpoint; LMT carries the name above it.
|
|
110
|
+
def stored_stereotype_position(connector, points)
|
|
111
|
+
return nil unless connector.is_a?(Ea::Model::DiagramConnector) && measured_name_font?
|
|
112
|
+
return nil unless stereotype_label(connector)
|
|
113
|
+
|
|
114
|
+
box = connector.label_boxes.to_h[:lmb]
|
|
115
|
+
return nil unless default_name_box?(box)
|
|
116
|
+
|
|
117
|
+
stored_position(connector, points, box, LINE_PITCH)
|
|
118
|
+
end
|
|
119
|
+
|
|
109
120
|
# At 7pt, a centered name's stored corner is 3px below its baseline.
|
|
110
121
|
def stored_name_position(connector, points)
|
|
111
|
-
|
|
122
|
+
stored_position(connector, points, stored_name_box(connector), -3)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def stored_position(connector, points, box, baseline)
|
|
112
126
|
return nil unless box
|
|
113
127
|
|
|
114
128
|
width = Ea::Fonts::Metrics.text_length(midpoint_content(connector), font_size, family: font_family)
|
|
@@ -116,7 +130,7 @@ module Ea
|
|
|
116
130
|
|
|
117
131
|
x, y = midpoint(points)
|
|
118
132
|
offset_x, offset_y = box.values_at("ox", "oy").map(&:to_i)
|
|
119
|
-
[x + offset_x - (width / 2.0).floor, y + offset_y
|
|
133
|
+
[x + offset_x - (width / 2.0).floor, y + offset_y + baseline]
|
|
120
134
|
end
|
|
121
135
|
|
|
122
136
|
def stored_name_box(connector)
|
|
@@ -129,7 +129,7 @@ module Ea
|
|
|
129
129
|
|
|
130
130
|
box = source_dock_bounds(connector)
|
|
131
131
|
face = box && dock_face_heading(points.first, box)
|
|
132
|
-
return face if face &&
|
|
132
|
+
return face if face && face_leads_leg?(connector, face, heading, box)
|
|
133
133
|
|
|
134
134
|
stored_upward_heading(connector, heading)
|
|
135
135
|
end
|
|
@@ -147,6 +147,18 @@ module Ea
|
|
|
147
147
|
original.any?(&:zero?) ? original : heading
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
+
# A saved external ray enters the source through the face it first
|
|
151
|
+
# meets, even when the clipped leg then runs back across the box.
|
|
152
|
+
def face_leads_leg?(connector, face, heading, box)
|
|
153
|
+
anchor = connector.source_anchor
|
|
154
|
+
if face == [0, 1] && anchor && anchor.y > box.y + box.height &&
|
|
155
|
+
connector.style.to_h[:stored_association_ray] == true
|
|
156
|
+
return true
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
face.zip(heading).any? { |axis, delta| (axis * delta).positive? }
|
|
160
|
+
end
|
|
161
|
+
|
|
150
162
|
def stored_upward_heading(connector, heading)
|
|
151
163
|
return heading unless heading[1].negative?
|
|
152
164
|
|
data/lib/ea/version.rb
CHANGED