ea 0.6.120 → 0.6.121

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.
@@ -9,7 +9,9 @@ module Ea
9
9
  #
10
10
  # Layer style keys:
11
11
  # - :diamond_filled → 4-pt <polygon>, black fill
12
+ # - :diamond_hollow → 4-pt <polygon>, white fill
12
13
  # - :triangle_open → 3-pt <polygon>, white fill
14
+ # - :nesting_circle → <ellipse> + plus <path>, white fill
13
15
  # - :arrow → 3-pt <path>, no fill (shares style with
14
16
  # connector lines — same stroke, no fill)
15
17
  #
@@ -48,22 +50,19 @@ module Ea
48
50
 
49
51
  def layers
50
52
  entries = visible_connectors.flat_map { |c| entries_for(c) }
51
- return [] if entries.empty?
52
53
 
53
54
  if grouped
54
- entries.group_by(&:style_key).map do |key, grouped_entries|
55
+ entries.group_by { |e| [e.style_key, e.stroke_width] }.map do |(key, width), grouped_entries|
55
56
  # EA emits ONE marker per connector regardless of
56
57
  # anchor overlap. Verified against plateau Bridge
57
58
  # diagram: 9 generalizations fanning from the same
58
59
  # parent anchor produce 9 distinct triangle polygons
59
60
  # at the same coordinates. The earlier "dedup by
60
61
  # anchor" hypothesis is disproven by reference SVGs.
61
- Layer.new(style_key: key,
62
- style: style_for(key),
63
- body: grouped_entries.map(&:body).join("\n "))
62
+ marker_layer(key, width, grouped_entries.map(&:body).join("\n "))
64
63
  end
65
64
  else
66
- entries.map { |e| Layer.new(style_key: e.style_key, style: style_for(e.style_key), body: e.body) }
65
+ entries.map { |e| marker_layer(e.style_key, e.stroke_width, e.body) }
67
66
  end
68
67
  end
69
68
 
@@ -86,7 +85,7 @@ module Ea
86
85
  # for future use (e.g. overlap diagnostics) but no longer
87
86
  # drives dedup — EA emits one marker per connector.
88
87
  Entry = Struct.new(:style_key, :body, :anchor,
89
- :connector_waypoint_count,
88
+ :connector_waypoint_count, :stroke_width,
90
89
  keyword_init: true) do
91
90
  def hash
92
91
  anchor.hash
@@ -109,13 +108,17 @@ module Ea
109
108
  style_key: :diamond_filled,
110
109
  render: ->(m, anchor, base) { m.diamond_polygon(anchor, base) }
111
110
  },
111
+ diamond_hollow: {
112
+ style_key: :diamond_hollow,
113
+ render: ->(m, anchor, base) { m.diamond_polygon(anchor, base) }
114
+ },
112
115
  triangle: {
113
116
  style_key: :triangle_open,
114
117
  render: ->(m, anchor, base) { m.triangle_polygon(anchor, base) }
115
118
  },
116
- plus: {
117
- style_key: :connector_line,
118
- render: ->(m, anchor, _base) { m.plus_path(anchor) }
119
+ nesting: {
120
+ style_key: :nesting_circle,
121
+ render: ->(m, anchor, base) { m.nesting_marker(anchor, base) }
119
122
  },
120
123
  arrow: {
121
124
  style_key: :connector_line,
@@ -124,10 +127,6 @@ module Ea
124
127
  dependency_arrow: {
125
128
  style_key: :connector_line,
126
129
  render: ->(m, anchor, base) { m.dependency_arrow_path(anchor, base) }
127
- },
128
- package_anchor: {
129
- style_key: :connector_line,
130
- render: ->(m, anchor, base) { m.package_anchor_path(anchor, base) }
131
130
  }
132
131
  }.freeze
133
132
 
@@ -135,15 +134,22 @@ module Ea
135
134
  # is shared, so only the fill and opacity vary.
136
135
  STYLE_MAP = {
137
136
  diamond_filled: { fill: "#000000", opacity: "1.00" },
137
+ diamond_hollow: { fill: "#FFFFFF", opacity: "1.00" },
138
138
  triangle_open: { fill: "#FFFFFF", opacity: "1.00" },
139
+ nesting_circle: { fill: "#FFFFFF", opacity: "1.00" },
139
140
  connector_line: { fill: "#000000", opacity: "0.00" }
140
141
  }.freeze
141
142
 
142
- def style_for(key)
143
+ def marker_layer(key, width, body)
144
+ Layer.new(style_key: Connectors.layer_key(key, width, stroke_width),
145
+ style: style_for(key, width), body: body)
146
+ end
147
+
148
+ def style_for(key, width = stroke_width)
143
149
  spec = STYLE_MAP[key]
144
150
  return nil unless spec
145
151
 
146
- "stroke-width:#{stroke_width};stroke-linecap:round;stroke-linejoin:bevel; " \
152
+ "stroke-width:#{width};stroke-linecap:round;stroke-linejoin:bevel; " \
147
153
  "fill:#{spec[:fill]};fill-opacity:#{spec[:opacity]}; " \
148
154
  "stroke:#000000; stroke-opacity:1.00"
149
155
  end
@@ -164,7 +170,8 @@ module Ea
164
170
  Entry.new(style_key: style_key_for(spec),
165
171
  body: body,
166
172
  anchor: anchor_for(spec),
167
- connector_waypoint_count: waypoint_count)
173
+ connector_waypoint_count: waypoint_count,
174
+ stroke_width: Connectors.stroke_width_for(connector, stroke_width))
168
175
  end
169
176
  end
170
177
 
@@ -279,22 +286,36 @@ module Ea
279
286
  entry[:render].call(self, spec.anchor, spec.base)
280
287
  end
281
288
 
282
- # Plus marker: two crossed line segments at the anchor.
283
- # EA encodes as one <path> with two sub-paths:
284
- # M cx cy-8 L cx cy+8 (vertical arm)
285
- # M cx+8 cy L cx-8 cy (horizontal arm)
286
- def plus_path(anchor)
287
- cx, cy = translate_point(anchor)
288
- cx_str = Canvas.coord(cx)
289
- cy_str = Canvas.coord(cy)
290
- up = Canvas.coord(cy - Marker::Plus::ARM_LENGTH)
291
- down = Canvas.coord(cy + Marker::Plus::ARM_LENGTH)
292
- left = Canvas.coord(cx - Marker::Plus::ARM_LENGTH)
293
- right = Canvas.coord(cx + Marker::Plus::ARM_LENGTH)
294
- d = "M #{cx_str} #{up} L #{cx_str} #{down} M #{right} #{cy_str} L #{left} #{cy_str}"
289
+ # Nesting marker: a white circle tangent to the container edge
290
+ # at the anchor, with a plus through its centre. The plus is an
291
+ # unfilled path, so it stays visible on the circle's fill.
292
+ def nesting_marker(tip, base)
293
+ tx, ty = translate_point(tip)
294
+ bx, by = translate_point(base)
295
+ ux, uy = unit_vector(tx, ty, bx, by)
296
+ return nil unless ux
297
+
298
+ radius = Marker::Plus::ARM_LENGTH
299
+ cx_val = tx - ux * radius
300
+ cy_val = ty - uy * radius
301
+ circle = %(<ellipse cx="#{fixed(cx_val)}" cy="#{fixed(cy_val)}" ) +
302
+ %(rx="#{radius}.00" ry="#{radius}.00" shape-rendering="auto" />)
303
+ [circle, plus_path(cx_val, cy_val)].join("\n ")
304
+ end
305
+
306
+ def plus_path(center_x, center_y)
307
+ arm = Marker::Plus::ARM_LENGTH
308
+ d = "M #{Canvas.coord(center_x)} #{Canvas.coord(center_y - arm)} " \
309
+ "L #{Canvas.coord(center_x)} #{Canvas.coord(center_y + arm)} " \
310
+ "M #{Canvas.coord(center_x + arm)} #{Canvas.coord(center_y)} " \
311
+ "L #{Canvas.coord(center_x - arm)} #{Canvas.coord(center_y)}"
295
312
  %(<path d="#{d}" shape-rendering="auto"/>)
296
313
  end
297
314
 
315
+ def fixed(value)
316
+ format("%<value>.2f", value: value)
317
+ end
318
+
298
319
  def specs_for(connector)
299
320
  points = waypoint_pairs(connector)
300
321
  return [] if points.size < 2
@@ -387,38 +408,6 @@ module Ea
387
408
  %(<path d="#{d}" shape-rendering="auto"/>)
388
409
  end
389
410
 
390
- # «import» source-end marker: a small closed trapezoid that
391
- # visually represents the imported package. Shape is a 4-point
392
- # polygon: top edge shorter than bottom edge, centered on the
393
- # anchor point.
394
- PACKAGE_ANCHOR_W = 5
395
- PACKAGE_ANCHOR_H_TOP = 3
396
- PACKAGE_ANCHOR_H_BOTTOM = 4
397
-
398
- def package_anchor_path(tip, base)
399
- tx, ty = translate_point(tip)
400
- bx, by = translate_point(base)
401
- ux, uy = unit_vector(tx, ty, bx, by)
402
- return nil unless ux
403
-
404
- back_x = tx - ux * PACKAGE_ANCHOR_H_BOTTOM
405
- back_y = ty - uy * PACKAGE_ANCHOR_H_BOTTOM
406
- tl_x = tx - ux * PACKAGE_ANCHOR_H_TOP + (-uy) * PACKAGE_ANCHOR_W
407
- tl_y = ty - uy * PACKAGE_ANCHOR_H_TOP + ux * PACKAGE_ANCHOR_W
408
- tr_x = tx - ux * PACKAGE_ANCHOR_H_TOP - (-uy) * PACKAGE_ANCHOR_W
409
- tr_y = ty - uy * PACKAGE_ANCHOR_H_TOP - ux * PACKAGE_ANCHOR_W
410
- bl_x = back_x + (-uy) * (PACKAGE_ANCHOR_W + 1)
411
- bl_y = back_y + ux * (PACKAGE_ANCHOR_W + 1)
412
- br_x = back_x - (-uy) * (PACKAGE_ANCHOR_W + 1)
413
- br_y = back_y - ux * (PACKAGE_ANCHOR_W + 1)
414
- d = "M #{Canvas.coord(tl_x)} #{Canvas.coord(tl_y)} " \
415
- "L #{Canvas.coord(tr_x)} #{Canvas.coord(tr_y)} " \
416
- "L #{Canvas.coord(br_x)} #{Canvas.coord(br_y)} " \
417
- "L #{Canvas.coord(bl_x)} #{Canvas.coord(bl_y)} " \
418
- "L #{Canvas.coord(tl_x)} #{Canvas.coord(tl_y)} Z"
419
- %(<path d="#{d}" shape-rendering="auto"/>)
420
- end
421
-
422
411
  # Dependency arrowhead: same open-path form as arrow_path
423
412
  # but EA's slimmer base-10 template. Coordinates are whole
424
413
  # pixels in EA's output (e.g. "M 2732 183 L 2747 178
@@ -449,8 +438,8 @@ module Ea
449
438
 
450
439
  [dx / len, dy / len]
451
440
  end
452
- public :diamond_polygon, :triangle_polygon, :plus_path,
453
- :arrow_path, :dependency_arrow_path, :package_anchor_path
441
+ public :diamond_polygon, :triangle_polygon, :nesting_marker,
442
+ :arrow_path, :dependency_arrow_path
454
443
 
455
444
  def translate_point(p)
456
445
  return p unless @canvas
data/lib/ea/version.rb CHANGED
@@ -4,5 +4,5 @@ module Ea
4
4
  # Gem release version. Extracted to its own file so the
5
5
  # `gem-release` tool's `gem bump` can find and update it via the
6
6
  # standard `lib/<gem>/version.rb` convention.
7
- VERSION = "0.6.120"
7
+ VERSION = "0.6.121"
8
8
  end
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.120
4
+ version: 0.6.121
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.