ea 0.6.33 → 0.6.34
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/sources/qea/diagram_builder.rb +5 -1
- data/lib/ea/svg/ea_emitter/connector_redock.rb +111 -0
- data/lib/ea/svg/ea_emitter/connectors.rb +9 -3
- data/lib/ea/svg/ea_emitter/elements.rb +44 -0
- data/lib/ea/svg/ea_emitter/layer_sequencer.rb +16 -4
- data/lib/ea/svg/ea_emitter/markers.rb +9 -2
- data/lib/ea/svg/ea_emitter.rb +1 -0
- data/lib/ea/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 413c25c403cee775eaf2cc7b49954dc9283434f49a501eff38250f0119dd58aa
|
|
4
|
+
data.tar.gz: bc4dbf0fec7e3c79e79ee4640711251b430f5c8dae6f002f491ac00b6f9f9f01
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 05cc5764a8a7ab8714ff1a2102513fbc15ebd77998651fc51ddcff7171c11896c0a27dc8fc0712f506f246c7177b5adc50bc72176fc4f265b866e6eed7334946
|
|
7
|
+
data.tar.gz: ee8ee21e94a4f073ad89a371cc638d118e7cbce4dd33f0179dee239fb182a1824546aacb25b77ed678e362aa3a24165dd9a75834a4cdac612dd02cad834b64bf
|
|
@@ -187,7 +187,11 @@ module Ea
|
|
|
187
187
|
# and associations draw as plain source-first lines
|
|
188
188
|
# (0CABA7D7's gen "M 125 130 L 125 99"; 568CDFC9's
|
|
189
189
|
# regenerated assocs).
|
|
190
|
-
style: conn.connector_type == "Dependency"
|
|
190
|
+
style: if conn.connector_type == "Dependency"
|
|
191
|
+
{ direct: true, regenerated: true }
|
|
192
|
+
else
|
|
193
|
+
{ regenerated: true }
|
|
194
|
+
end,
|
|
191
195
|
hidden: false,
|
|
192
196
|
has_geometry_offsets: false
|
|
193
197
|
)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
# Re-docks DIRECT (auto-routed straight, 2-waypoint) connectors
|
|
7
|
+
# against the DRAWN element outlines captured during the element
|
|
8
|
+
# render pass. EA clips connector rays at drawn boxes — grown
|
|
9
|
+
# classifier heights and autosized package bodies — never the
|
|
10
|
+
# stored logical rect (E58034A3: supplier right-edge dock 155
|
|
11
|
+
# drawn vs 121 stored; 0CABA7D7's generalization far end 99
|
|
12
|
+
# grown vs 84 stored).
|
|
13
|
+
module ConnectorRedock
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# Returns replacement waypoint pairs [source_edge, target_edge]
|
|
17
|
+
# for the connector, or nil when the connector must keep its
|
|
18
|
+
# parsed waypoints (not direct, not 2-point, unresolved ends,
|
|
19
|
+
# self-loop, or no drawn bounds for either end).
|
|
20
|
+
def pairs_for(connector, diagram, model_index, bounds_map)
|
|
21
|
+
return nil unless bounds_map
|
|
22
|
+
return nil unless direct?(connector)
|
|
23
|
+
|
|
24
|
+
points = waypoint_pairs(connector)
|
|
25
|
+
return nil unless points.size == 2
|
|
26
|
+
|
|
27
|
+
rel = relationship_for(connector, model_index)
|
|
28
|
+
return nil unless rel
|
|
29
|
+
|
|
30
|
+
source_ref, target_ref = end_refs(rel)
|
|
31
|
+
return nil unless source_ref && target_ref
|
|
32
|
+
|
|
33
|
+
source_bounds = bounds_map[source_ref]
|
|
34
|
+
target_bounds = bounds_map[target_ref]
|
|
35
|
+
return nil unless source_bounds && target_bounds
|
|
36
|
+
return nil if source_ref == target_ref
|
|
37
|
+
|
|
38
|
+
[edge_point(source_bounds, target_bounds),
|
|
39
|
+
edge_point(target_bounds, source_bounds)]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def direct?(connector)
|
|
43
|
+
style = connector.style || {}
|
|
44
|
+
%i[direct regenerated].any? { |k| style.key?(k) } ||
|
|
45
|
+
%w[direct regenerated].any? { |k| style.key?(k) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def waypoint_pairs(connector)
|
|
49
|
+
(connector.waypoints || []).filter_map do |wp|
|
|
50
|
+
next unless wp.position
|
|
51
|
+
|
|
52
|
+
[wp.position.x, wp.position.y]
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def relationship_for(connector, model_index)
|
|
57
|
+
return nil unless connector.relationship_ref && model_index
|
|
58
|
+
|
|
59
|
+
model_index[connector.relationship_ref]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Polymorphic relationship ends, in connector start→end
|
|
63
|
+
# order: Generalization child→parent (specific_id/general_id),
|
|
64
|
+
# Dependency client→supplier (client_id/supplier_id),
|
|
65
|
+
# Association source_id/target_id.
|
|
66
|
+
def end_refs(rel)
|
|
67
|
+
if rel.respond_to?(:specific_id)
|
|
68
|
+
[rel.specific_id, rel.general_id]
|
|
69
|
+
elsif rel.respond_to?(:client_id)
|
|
70
|
+
[rel.client_id, rel.supplier_id]
|
|
71
|
+
else
|
|
72
|
+
[rel.source_id, rel.target_id]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Center-to-center ray clipped at both box outlines.
|
|
77
|
+
def edge_point(bounds, other_bounds)
|
|
78
|
+
cx = bounds.x + bounds.width / 2
|
|
79
|
+
cy = bounds.y + bounds.height / 2
|
|
80
|
+
ocx = other_bounds.x + other_bounds.width / 2
|
|
81
|
+
ocy = other_bounds.y + other_bounds.height / 2
|
|
82
|
+
|
|
83
|
+
dx = ocx - cx
|
|
84
|
+
dy = ocy - cy
|
|
85
|
+
|
|
86
|
+
if dx.abs * bounds.height > dy.abs * bounds.width
|
|
87
|
+
x = dx.positive? ? bounds.x + bounds.width : bounds.x
|
|
88
|
+
y = safe_y(cx, cy, dx, dy, x)
|
|
89
|
+
[x, y]
|
|
90
|
+
else
|
|
91
|
+
y = dy.positive? ? bounds.y + bounds.height : bounds.y
|
|
92
|
+
x = safe_x(cx, cy, dx, dy, y)
|
|
93
|
+
[x, y]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def safe_y(cx, cy, dx, dy, x)
|
|
98
|
+
return cy if dx.zero?
|
|
99
|
+
|
|
100
|
+
cy + dy * (x - cx).abs / dx.abs
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def safe_x(cx, cy, dx, dy, y)
|
|
104
|
+
return cx if dy.zero?
|
|
105
|
+
|
|
106
|
+
cx + dx * (y - cy).abs / dy.abs
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -16,13 +16,17 @@ module Ea
|
|
|
16
16
|
class Connectors
|
|
17
17
|
LINE_STYLE_KEY = :connector_line
|
|
18
18
|
|
|
19
|
-
attr_reader :diagram, :canvas, :grouped, :stroke_width
|
|
19
|
+
attr_reader :diagram, :canvas, :grouped, :stroke_width, :drawn_bounds,
|
|
20
|
+
:model_index
|
|
20
21
|
|
|
21
|
-
def initialize(diagram, canvas: nil, grouped: true, stroke_width: 2
|
|
22
|
+
def initialize(diagram, canvas: nil, grouped: true, stroke_width: 2,
|
|
23
|
+
drawn_bounds: nil, model_index: nil)
|
|
22
24
|
@diagram = diagram
|
|
23
25
|
@canvas = canvas
|
|
24
26
|
@grouped = grouped
|
|
25
27
|
@stroke_width = stroke_width
|
|
28
|
+
@drawn_bounds = drawn_bounds
|
|
29
|
+
@model_index = model_index
|
|
26
30
|
end
|
|
27
31
|
|
|
28
32
|
def layers
|
|
@@ -55,7 +59,9 @@ module Ea
|
|
|
55
59
|
end
|
|
56
60
|
|
|
57
61
|
def path_for(connector)
|
|
58
|
-
pts =
|
|
62
|
+
pts = ConnectorRedock.pairs_for(connector, diagram, model_index,
|
|
63
|
+
drawn_bounds) ||
|
|
64
|
+
waypoints_for(connector)
|
|
59
65
|
return nil if pts.size < 2
|
|
60
66
|
|
|
61
67
|
# DIRECT (auto-routed straight) connectors: EA writes the
|
|
@@ -31,9 +31,17 @@ module Ea
|
|
|
31
31
|
# Each element contributes up to 4 groups (shape, header,
|
|
32
32
|
# divider, attrs) in EA's per-entity layer order.
|
|
33
33
|
def groups
|
|
34
|
+
@drawn_bounds = {}
|
|
34
35
|
ordered_elements.flat_map { |e| groups_for(e) }
|
|
35
36
|
end
|
|
36
37
|
|
|
38
|
+
# Final drawn Bounds per model element reference, captured
|
|
39
|
+
# during rendering (grown heights for overflowing classifiers,
|
|
40
|
+
# autosized outlines for packages). Connector emission re-docks
|
|
41
|
+
# direct lines against these — EA clips connector rays at the
|
|
42
|
+
# drawn outlines, never the stored rect.
|
|
43
|
+
attr_reader :drawn_bounds
|
|
44
|
+
|
|
37
45
|
private
|
|
38
46
|
|
|
39
47
|
def ordered_elements
|
|
@@ -46,9 +54,45 @@ module Ea
|
|
|
46
54
|
context = build_context(element)
|
|
47
55
|
return [] unless context
|
|
48
56
|
|
|
57
|
+
record_drawn_bounds(element, context)
|
|
49
58
|
Compartment.render_all(context).compact
|
|
50
59
|
end
|
|
51
60
|
|
|
61
|
+
# Logical-space drawn bounds: stored x/y with the RENDERED
|
|
62
|
+
# height (grown classifiers) and rendered width (autosized
|
|
63
|
+
# packages). Heights/widths are translation-invariant, so the
|
|
64
|
+
# connector emitters can redock in logical space and run the
|
|
65
|
+
# normal canvas translation afterwards.
|
|
66
|
+
def record_drawn_bounds(element, context)
|
|
67
|
+
return unless element.model_element_ref
|
|
68
|
+
|
|
69
|
+
raw = element.bounds || element.image_bounds
|
|
70
|
+
return unless raw
|
|
71
|
+
|
|
72
|
+
width = raw.width
|
|
73
|
+
if classifier_package?(context.classifier)
|
|
74
|
+
tab = Element::PackageShapeRenderer.autosized_tab_width(
|
|
75
|
+
label: context.classifier.name.to_s,
|
|
76
|
+
stereotype: package_stereotype(context),
|
|
77
|
+
size: context.size
|
|
78
|
+
)
|
|
79
|
+
width = tab + Element::PackageShapeRenderer::TAB_BODY_EXTRA
|
|
80
|
+
end
|
|
81
|
+
@drawn_bounds[element.model_element_ref] = Ea::Model::Bounds.new(
|
|
82
|
+
x: raw.x, y: raw.y,
|
|
83
|
+
width: width,
|
|
84
|
+
height: context.bounds.height
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def classifier_package?(classifier)
|
|
89
|
+
classifier.class == Ea::Model::Package
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def package_stereotype(context)
|
|
93
|
+
context.classifier.stereotype_refs.first.to_s
|
|
94
|
+
end
|
|
95
|
+
|
|
52
96
|
# Build the RenderContext for one element. Returns nil when
|
|
53
97
|
# the element has no usable bounds (skip rendering).
|
|
54
98
|
def build_context(element)
|
|
@@ -42,6 +42,13 @@ module Ea
|
|
|
42
42
|
layers
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
# Final drawn Bounds per model element ref (grown heights,
|
|
46
|
+
# autosized packages) captured by the element pass; connector
|
|
47
|
+
# emission re-docks direct lines against these.
|
|
48
|
+
def drawn_bounds
|
|
49
|
+
@elements&.drawn_bounds
|
|
50
|
+
end
|
|
51
|
+
|
|
45
52
|
private
|
|
46
53
|
|
|
47
54
|
def frame_layers
|
|
@@ -49,17 +56,22 @@ module Ea
|
|
|
49
56
|
end
|
|
50
57
|
|
|
51
58
|
def element_layers
|
|
52
|
-
Elements.new(diagram, model_index: model_index,
|
|
53
|
-
|
|
59
|
+
@elements = Elements.new(diagram, model_index: model_index,
|
|
60
|
+
canvas: canvas,
|
|
61
|
+
document: document)
|
|
62
|
+
@elements.groups
|
|
54
63
|
end
|
|
55
64
|
|
|
56
65
|
def connector_layers
|
|
57
66
|
connector_layers_raw = Connectors.new(diagram, canvas: canvas,
|
|
58
67
|
grouped: true,
|
|
59
|
-
stroke_width: DEFAULT_STROKE_WIDTH
|
|
68
|
+
stroke_width: DEFAULT_STROKE_WIDTH,
|
|
69
|
+
drawn_bounds: drawn_bounds,
|
|
70
|
+
model_index: model_index).layers
|
|
60
71
|
marker_layers_raw = Markers.new(diagram, model_index: model_index,
|
|
61
72
|
canvas: canvas, grouped: true,
|
|
62
|
-
stroke_width: DEFAULT_STROKE_WIDTH
|
|
73
|
+
stroke_width: DEFAULT_STROKE_WIDTH,
|
|
74
|
+
drawn_bounds: drawn_bounds).layers
|
|
63
75
|
merge_layers_by_style(connector_layers_raw + marker_layers_raw).map(&:to_svg)
|
|
64
76
|
end
|
|
65
77
|
|
|
@@ -31,14 +31,17 @@ module Ea
|
|
|
31
31
|
DEP_ARROW_HALF_BASE = 5
|
|
32
32
|
DEP_ARROW_HEIGHT = 15
|
|
33
33
|
|
|
34
|
-
attr_reader :diagram, :model_index, :canvas, :grouped, :stroke_width
|
|
34
|
+
attr_reader :diagram, :model_index, :canvas, :grouped, :stroke_width,
|
|
35
|
+
:drawn_bounds
|
|
35
36
|
|
|
36
|
-
def initialize(diagram, model_index:, canvas: nil, grouped: true,
|
|
37
|
+
def initialize(diagram, model_index:, canvas: nil, grouped: true,
|
|
38
|
+
stroke_width: 2, drawn_bounds: nil)
|
|
37
39
|
@diagram = diagram
|
|
38
40
|
@model_index = model_index
|
|
39
41
|
@canvas = canvas
|
|
40
42
|
@grouped = grouped
|
|
41
43
|
@stroke_width = stroke_width
|
|
44
|
+
@drawn_bounds = drawn_bounds
|
|
42
45
|
end
|
|
43
46
|
|
|
44
47
|
def layers
|
|
@@ -454,6 +457,10 @@ module Ea
|
|
|
454
457
|
end
|
|
455
458
|
|
|
456
459
|
def waypoint_pairs(connector)
|
|
460
|
+
redocked = ConnectorRedock.pairs_for(connector, diagram,
|
|
461
|
+
model_index, drawn_bounds)
|
|
462
|
+
return redocked if redocked
|
|
463
|
+
|
|
457
464
|
(connector.waypoints || []).filter_map do |w|
|
|
458
465
|
next unless w.position
|
|
459
466
|
|
data/lib/ea/svg/ea_emitter.rb
CHANGED
|
@@ -45,6 +45,7 @@ module Ea
|
|
|
45
45
|
autoload :Document, "ea/svg/ea_emitter/document"
|
|
46
46
|
autoload :Label, "ea/svg/ea_emitter/label"
|
|
47
47
|
autoload :Compartment, "ea/svg/ea_emitter/compartment"
|
|
48
|
+
autoload :ConnectorRedock, "ea/svg/ea_emitter/connector_redock"
|
|
48
49
|
autoload :RenderContext, "ea/svg/ea_emitter/render_context"
|
|
49
50
|
autoload :VisibilitySymbol, "ea/svg/ea_emitter/visibility_symbol"
|
|
50
51
|
end
|
data/lib/ea/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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.34
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|
|
@@ -894,6 +894,7 @@ files:
|
|
|
894
894
|
- lib/ea/svg/ea_emitter/compartment/shape.rb
|
|
895
895
|
- lib/ea/svg/ea_emitter/compartment/stereotype_icon.rb
|
|
896
896
|
- lib/ea/svg/ea_emitter/compartment/tagged_values.rb
|
|
897
|
+
- lib/ea/svg/ea_emitter/connector_redock.rb
|
|
897
898
|
- lib/ea/svg/ea_emitter/connectors.rb
|
|
898
899
|
- lib/ea/svg/ea_emitter/diagram_frame.rb
|
|
899
900
|
- lib/ea/svg/ea_emitter/document.rb
|