rsyntaxtree 1.6.0 → 1.6.2
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/CHANGELOG.md +21 -0
- data/docs/_examples/065.md +22 -0
- data/docs/assets/img/064.png +0 -0
- data/docs/assets/img/065.png +0 -0
- data/docs/assets/svg/064.svg +3 -3
- data/docs/assets/svg/065.svg +54 -0
- data/lib/rsyntaxtree/base_graph.rb +0 -20
- data/lib/rsyntaxtree/svg_graph.rb +95 -13
- data/lib/rsyntaxtree/version.rb +1 -1
- data/test/node_styling_test.rb +21 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f13f7407a77bda563986883ec33eed5c2699305e73428582e0caf2c64c7cdf22
|
|
4
|
+
data.tar.gz: 329f1d4357b0034709bd842f117c14ea401dad18b7ca72e65b917149fcc794a9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4bab8dc69ae2631ae4818e41a2b986136ab9b40e20a6e9bd2e4793b745e605193f35920e5679e48f5e37bc89211c26e2a1f659a432292c2fd3c027fe35063ae1
|
|
7
|
+
data.tar.gz: 36db33880b172ac48da638dc0de97797481c88ca6af3bddb632cb1e5f7f795d5146ad1cac5d29f242213157bd16a8c44e031c690d55561fd73076be4bb2dde0e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.2] - 2026-06
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Region shade no longer touches the image edge when its padded bounds reach
|
|
7
|
+
past the tree's natural extent (e.g. a deep enclosed/multi-line node): the
|
|
8
|
+
canvas now grows with a margin around the shaded plane.
|
|
9
|
+
|
|
10
|
+
## [1.6.1] - 2026-06
|
|
11
|
+
|
|
12
|
+
### Improved
|
|
13
|
+
- Region shade rendering wraps the subtree more cleanly: wider, balanced
|
|
14
|
+
padding; bracket/rectangle enclosures are kept inside the plane; the incoming
|
|
15
|
+
parent connector stops just short of the plane (no overlap or touching); and
|
|
16
|
+
the margin is consistent between root and non-root regions. Works in both
|
|
17
|
+
top-to-bottom and left-to-right layouts (the connector-facing edge is the top
|
|
18
|
+
in TTB and the left in LTR, with symmetric padding on the other sides).
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- Example 065: nested (overlapping) region shades, shown as progressively
|
|
22
|
+
darker gray.
|
|
23
|
+
|
|
3
24
|
## [1.6.0] - 2026-06
|
|
4
25
|
|
|
5
26
|
### Added
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "065"
|
|
3
|
+
caption: "Nested region shades (overlapping domains)"
|
|
4
|
+
category: "Generative Grammar"
|
|
5
|
+
color: "off"
|
|
6
|
+
polyline: "off"
|
|
7
|
+
symmetrization: "off"
|
|
8
|
+
connector: "auto"
|
|
9
|
+
connector_height: "2.0"
|
|
10
|
+
linewidth: "1"
|
|
11
|
+
hide_default_connectors: "off"
|
|
12
|
+
font: "Noto Serif"
|
|
13
|
+
---
|
|
14
|
+
```
|
|
15
|
+
[%S
|
|
16
|
+
[DP everyone]
|
|
17
|
+
[%VP
|
|
18
|
+
[V loves]
|
|
19
|
+
[%NP Mary]
|
|
20
|
+
]
|
|
21
|
+
]
|
|
22
|
+
```
|
data/docs/assets/img/064.png
CHANGED
|
Binary file
|
|
Binary file
|
data/docs/assets/svg/064.svg
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<?xml version="1.0" standalone="no"?>
|
|
2
2
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
3
|
-
<svg width="743.6000000000001" height="
|
|
3
|
+
<svg width="743.6000000000001" height="782.075" viewBox="-17.6, 0, 761.2000000000002, 793.325" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
|
4
4
|
<defs>
|
|
5
5
|
<marker id="arrow" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="17.6" markerHeight="17.6" orient="auto">
|
|
6
6
|
<path d="M 0 0 L 10 5 L 0 10" fill="#CC79A7"/>
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
<line x1="0" y="0" x2="0" y2="10" stroke="#009E73" stroke-width="4"></line>
|
|
25
25
|
</pattern>
|
|
26
26
|
</defs>
|
|
27
|
-
<rect x="-17.6" y="0" width="761.2000000000002" height="
|
|
28
|
-
<rect x='
|
|
27
|
+
<rect x="-17.6" y="0" width="761.2000000000002" height="793.325" stroke="none" fill="white" />"
|
|
28
|
+
<rect x='213.4' y='193.5' width='495.0000000000001' height='581.225' rx='11.25' ry='11.25' fill='lightblue' fill-opacity='0.2' stroke='lightblue' stroke-opacity='0.55' stroke-width='2' />
|
|
29
29
|
<text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='216.76250000000002' y='67.5'><tspan x='216.76250000000002' y='67.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">TP</tspan>
|
|
30
30
|
</text>
|
|
31
31
|
<text white-space='pre' alignment-baseline='text-top' style='fill: #0072B2; storoke-width: 0; font-size: 32px;' x='67.6' y='238.5'><tspan x='67.6' y='238.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">DP</tspan>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<?xml version="1.0" standalone="no"?>
|
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
3
|
+
<svg width="516.2" height="611.075" viewBox="-18.60000000000001, 0, 533.8000000000001, 622.325" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
|
4
|
+
<defs>
|
|
5
|
+
<marker id="arrow" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="17.6" markerHeight="17.6" orient="auto">
|
|
6
|
+
<path d="M 0 0 L 10 5 L 0 10" fill="black"/>
|
|
7
|
+
</marker>
|
|
8
|
+
<marker id="arrowBackward" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="17.6" markerHeight="17.6" orient="auto">
|
|
9
|
+
<path d="M 0 0 L 10 5 L 0 10 z" fill="black"/>
|
|
10
|
+
</marker>
|
|
11
|
+
<marker id="arrowForward" markerUnits="userSpaceOnUse" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="17.6" markerHeight="17.6" orient="auto">
|
|
12
|
+
<path d="M 10 0 L 0 5 L 10 10 z" fill="black"/>
|
|
13
|
+
</marker>
|
|
14
|
+
<marker id="arrowBothways" markerUnits="userSpaceOnUse" viewBox="0 0 30 10" refX="15" refY="5" markerWidth="52.800000000000004" markerHeight="17.6" orient="auto">
|
|
15
|
+
<path d="M 0 5 L 10 0 L 10 5 L 20 5 L 20 0 L 30 5 L 20 10 L 20 5 L 10 5 L 10 10 z" fill="black"/>
|
|
16
|
+
</marker>
|
|
17
|
+
<pattern id="hatchBlack" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
|
18
|
+
<line x1="0" y="0" x2="0" y2="10" stroke="black" stroke-width="4"></line>
|
|
19
|
+
</pattern>
|
|
20
|
+
<pattern id="hatchForNode" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
|
21
|
+
<line x1="0" y="0" x2="0" y2="10" stroke="black" stroke-width="4"></line>
|
|
22
|
+
</pattern>
|
|
23
|
+
<pattern id="hatchForLeaf" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
|
24
|
+
<line x1="0" y="0" x2="0" y2="10" stroke="black" stroke-width="4"></line>
|
|
25
|
+
</pattern>
|
|
26
|
+
</defs>
|
|
27
|
+
<rect x="-18.60000000000001" y="0" width="533.8000000000001" height="622.325" stroke="none" fill="white" />"
|
|
28
|
+
<rect x='-7.105427357601002e-15' y='22.5' width='480.0' height='581.225' rx='11.25' ry='11.25' fill='#888888' fill-opacity='0.2' stroke='#888888' stroke-opacity='0.55' stroke-width='2' />
|
|
29
|
+
<rect x='213.4' y='193.5' width='266.6' height='410.225' rx='11.25' ry='11.25' fill='#888888' fill-opacity='0.2' stroke='#888888' stroke-opacity='0.55' stroke-width='2' />
|
|
30
|
+
<rect x='362.79999999999995' y='364.5' width='117.20000000000005' height='239.22500000000002' rx='11.25' ry='11.25' fill='#888888' fill-opacity='0.2' stroke='#888888' stroke-opacity='0.55' stroke-width='2' />
|
|
31
|
+
<text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='208.525' y='67.5'><tspan x='208.525' y='67.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">S</tspan>
|
|
32
|
+
</text>
|
|
33
|
+
<text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='67.6' y='238.5'><tspan x='67.6' y='238.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">DP</tspan>
|
|
34
|
+
</text>
|
|
35
|
+
<text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='17.599999999999994' y='409.5'><tspan x='17.599999999999994' y='409.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">everyone</tspan>
|
|
36
|
+
</text>
|
|
37
|
+
<text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='325.45' y='238.5'><tspan x='325.45' y='238.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">VP</tspan>
|
|
38
|
+
</text>
|
|
39
|
+
<text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='259.5' y='409.5'><tspan x='259.5' y='409.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">V</tspan>
|
|
40
|
+
</text>
|
|
41
|
+
<text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='231.0' y='580.5'><tspan x='231.0' y='580.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">loves</tspan>
|
|
42
|
+
</text>
|
|
43
|
+
<text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='399.4' y='409.5'><tspan x='399.4' y='409.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">NP</tspan>
|
|
44
|
+
</text>
|
|
45
|
+
<text white-space='pre' alignment-baseline='text-top' style='fill: black; storoke-width: 0; font-size: 32px;' x='380.4' y='580.5'><tspan x='380.4' y='580.5' style="" text-decoration="" font-family="'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif">Mary</tspan>
|
|
46
|
+
</text>
|
|
47
|
+
<line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='89.1' y1='182.25' x2='217.525' y2='95.625' />
|
|
48
|
+
<line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='345.95' y1='182.25' x2='217.525' y2='95.625' />
|
|
49
|
+
<line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='89.1' y1='353.25' x2='89.1' y2='266.625' />
|
|
50
|
+
<line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='270.5' y1='353.25' x2='345.95' y2='266.625' />
|
|
51
|
+
<line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='421.4' y1='353.25' x2='345.95' y2='266.625' />
|
|
52
|
+
<line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='270.5' y1='524.25' x2='270.5' y2='437.625' />
|
|
53
|
+
<line style='fill: none; stroke:black; stroke-width:2; stroke-linejoin:round; stroke-linecap:round;' x1='421.4' y1='524.25' x2='421.4' y2='437.625' />
|
|
54
|
+
</svg>
|
|
@@ -236,26 +236,6 @@ module RSyntaxTree
|
|
|
236
236
|
end
|
|
237
237
|
end
|
|
238
238
|
|
|
239
|
-
# Bounding box of the subtree rooted at +id+, expressed in final drawing
|
|
240
|
-
# coordinates (horizontal_indent / vertical_indent / content_*). Works for
|
|
241
|
-
# both TTB and LTR because it runs after layout (and finalize_ltr) has
|
|
242
|
-
# placed every element. Used to draw whole-subtree region shades.
|
|
243
|
-
def subtree_bounds(id = 1)
|
|
244
|
-
el = @element_list.get_id(id)
|
|
245
|
-
left = el.horizontal_indent
|
|
246
|
-
right = el.horizontal_indent + el.content_width
|
|
247
|
-
top = el.vertical_indent
|
|
248
|
-
bottom = el.vertical_indent + el.content_height
|
|
249
|
-
el.children.each do |c|
|
|
250
|
-
cb = subtree_bounds(c)
|
|
251
|
-
left = cb[:left] if cb[:left] < left
|
|
252
|
-
right = cb[:right] if cb[:right] > right
|
|
253
|
-
top = cb[:top] if cb[:top] < top
|
|
254
|
-
bottom = cb[:bottom] if cb[:bottom] > bottom
|
|
255
|
-
end
|
|
256
|
-
{ left: left, right: right, top: top, bottom: bottom }
|
|
257
|
-
end
|
|
258
|
-
|
|
259
239
|
def get_leftmost(id = 1)
|
|
260
240
|
target = @element_list.get_id(id)
|
|
261
241
|
target_indent = target.horizontal_indent
|
|
@@ -69,14 +69,17 @@ module RSyntaxTree
|
|
|
69
69
|
y2 = @height + @global[:height_connector_to_text] / 2
|
|
70
70
|
|
|
71
71
|
# Grow the canvas so region shades that reach past the tree's own bounds
|
|
72
|
-
# (e.g. a region on the root node,
|
|
73
|
-
#
|
|
72
|
+
# (e.g. a region on the root node, or one whose padded edge extends beyond
|
|
73
|
+
# the deepest leaf) keep a margin instead of touching the image edge. A
|
|
74
|
+
# margin is added around the region extents before unioning with the tree
|
|
75
|
+
# bounds. x2/y2 are the viewBox width/height, so right = x1 + x2.
|
|
74
76
|
if @region_bounds
|
|
75
77
|
rb = @region_bounds
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
m = @global[:h_gap_between_nodes]
|
|
79
|
+
left = [x1, rb[:min_x] - m].min
|
|
80
|
+
top = [y1, rb[:min_y] - m].min
|
|
81
|
+
right = [x1 + x2, rb[:max_x] + m].max
|
|
82
|
+
bottom = [y1 + y2, rb[:max_y] + m].max
|
|
80
83
|
new_x2 = right - left
|
|
81
84
|
new_y2 = bottom - top
|
|
82
85
|
@width += new_x2 - x2
|
|
@@ -142,21 +145,57 @@ module RSyntaxTree
|
|
|
142
145
|
# Outer (shallower) regions are emitted first so deeper ones layer on
|
|
143
146
|
# top; with low opacity the overlap reads as a darker nesting.
|
|
144
147
|
def collect_region_shades
|
|
145
|
-
|
|
148
|
+
hctt = @global[:height_connector_to_text]
|
|
149
|
+
pad = @global[:h_gap_between_nodes] # generous padding for the non-parent-facing edges
|
|
150
|
+
pad_parent = hctt / 2.0 # tighter margin on the parent-facing edge of the root
|
|
151
|
+
radius = hctt / 2.0
|
|
146
152
|
stroke_width = @linewidth + LINE_SCALING
|
|
147
153
|
half = stroke_width / 2.0
|
|
148
154
|
@element_list.get_elements.each do |element|
|
|
149
155
|
next unless element.region
|
|
150
156
|
|
|
151
|
-
b =
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
b = region_subtree_bounds(element.id)
|
|
158
|
+
left = b[:left] - pad
|
|
159
|
+
right = b[:right] + pad
|
|
160
|
+
top = b[:top] - pad
|
|
161
|
+
bottom = b[:bottom] + pad
|
|
162
|
+
|
|
163
|
+
# The edge facing the parent is handled specially so the incoming
|
|
164
|
+
# connector neither overlaps nor touches the plane. That edge is the
|
|
165
|
+
# TOP in top-to-bottom layout and the LEFT in left-to-right layout; the
|
|
166
|
+
# other edges keep the generous padding. For a non-root node the edge
|
|
167
|
+
# is placed midway between the connector anchor and the content edge
|
|
168
|
+
# (even gap on both sides); the tree root has no incoming connector, so
|
|
169
|
+
# it just gets a tighter-but-consistent margin there.
|
|
170
|
+
is_root = element.parent.zero?
|
|
171
|
+
if @direction == "ltr"
|
|
172
|
+
anchor = element.horizontal_indent - hctt
|
|
173
|
+
left = if is_root
|
|
174
|
+
b[:left] - pad_parent
|
|
175
|
+
elsif anchor < b[:left]
|
|
176
|
+
(b[:left] + anchor) / 2.0
|
|
177
|
+
else
|
|
178
|
+
left
|
|
179
|
+
end
|
|
180
|
+
else
|
|
181
|
+
anchor = element.vertical_indent + hctt / 2.0
|
|
182
|
+
top = if is_root
|
|
183
|
+
b[:top] - pad_parent
|
|
184
|
+
elsif anchor < b[:top]
|
|
185
|
+
(b[:top] + anchor) / 2.0
|
|
186
|
+
else
|
|
187
|
+
top
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
x = left
|
|
192
|
+
y = top
|
|
193
|
+
w = right - left
|
|
194
|
+
h = bottom - top
|
|
156
195
|
# An explicit shade color is always honored (consistent with the
|
|
157
196
|
# @color: node-text color); bare '%' falls back to gray.
|
|
158
197
|
color = element.region_color || REGION_DEFAULT_COLOR
|
|
159
|
-
@region_shades << "<rect x='#{x}' y='#{y}' width='#{w}' height='#{h}' rx='#{
|
|
198
|
+
@region_shades << "<rect x='#{x}' y='#{y}' width='#{w}' height='#{h}' rx='#{radius}' ry='#{radius}' " \
|
|
160
199
|
"fill='#{color}' fill-opacity='#{REGION_FILL_OPACITY}' " \
|
|
161
200
|
"stroke='#{color}' stroke-opacity='#{REGION_STROKE_OPACITY}' stroke-width='#{stroke_width}' />\n"
|
|
162
201
|
|
|
@@ -170,6 +209,49 @@ module RSyntaxTree
|
|
|
170
209
|
end
|
|
171
210
|
end
|
|
172
211
|
|
|
212
|
+
# Visual bounding box of a single element as actually drawn: the label /
|
|
213
|
+
# enclosure box (which starts hctt*3/4 below vertical_indent, i.e. below the
|
|
214
|
+
# connector gap) widened to include any enclosure bracket/rectangle that is
|
|
215
|
+
# painted beyond the content width.
|
|
216
|
+
def element_visual_box(el)
|
|
217
|
+
hctt = @global[:height_connector_to_text]
|
|
218
|
+
box_top = el.vertical_indent + hctt * 3 / 4 # bc[:y]: line-height / enclosure box top
|
|
219
|
+
box_bottom = box_top + el.content_height
|
|
220
|
+
left = el.horizontal_indent
|
|
221
|
+
right = el.horizontal_indent + el.content_width
|
|
222
|
+
if [:brackets, :rectangle, :brectangle].include?(el.enclosure)
|
|
223
|
+
ext = @global[:h_gap_between_nodes] / 2 + (@linewidth + BLINE_SCALING)
|
|
224
|
+
left -= ext
|
|
225
|
+
right += ext
|
|
226
|
+
sw = @linewidth + BLINE_SCALING
|
|
227
|
+
top = box_top - sw
|
|
228
|
+
bottom = box_bottom + sw
|
|
229
|
+
else
|
|
230
|
+
# No enclosure box is painted, so hug the actual glyphs rather than the
|
|
231
|
+
# taller line-height box: the line box carries ~hctt*3/4 of leading both
|
|
232
|
+
# above the cap top and below the baseline, which would otherwise leave
|
|
233
|
+
# too much empty space above and below a plain label.
|
|
234
|
+
top = el.vertical_indent + hctt * 3 / 2
|
|
235
|
+
bottom = box_bottom - hctt * 3 / 4
|
|
236
|
+
end
|
|
237
|
+
{ left: left, top: top, right: right, bottom: bottom }
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Union of element_visual_box over the subtree rooted at +id+, in final
|
|
241
|
+
# drawing coordinates. Used to size region shades so the whole subtree
|
|
242
|
+
# (labels, enclosures, brackets) sits inside the plane.
|
|
243
|
+
def region_subtree_bounds(id)
|
|
244
|
+
b = element_visual_box(@element_list.get_id(id))
|
|
245
|
+
@element_list.get_id(id).children.each do |c|
|
|
246
|
+
cb = region_subtree_bounds(c)
|
|
247
|
+
b[:left] = cb[:left] if cb[:left] < b[:left]
|
|
248
|
+
b[:right] = cb[:right] if cb[:right] > b[:right]
|
|
249
|
+
b[:top] = cb[:top] if cb[:top] < b[:top]
|
|
250
|
+
b[:bottom] = cb[:bottom] if cb[:bottom] > b[:bottom]
|
|
251
|
+
end
|
|
252
|
+
b
|
|
253
|
+
end
|
|
254
|
+
|
|
173
255
|
def draw_a_path(s_x, s_y, t_x, t_y, target_arrow = :none)
|
|
174
256
|
spacing = @global[:h_gap_between_nodes] * 1.25
|
|
175
257
|
min_bulge = @global[:height_connector_to_text]
|
data/lib/rsyntaxtree/version.rb
CHANGED
data/test/node_styling_test.rb
CHANGED
|
@@ -322,6 +322,27 @@ class NodeStylingTest < Minitest::Test
|
|
|
322
322
|
assert rx + rw <= minx + vbw + eps, "region right clipped beyond viewBox"
|
|
323
323
|
end
|
|
324
324
|
|
|
325
|
+
def test_region_keeps_margin_from_canvas_edge
|
|
326
|
+
# Regression: when a region's padded bounds extend past the tree's natural
|
|
327
|
+
# extent (here an enclosed multi-line node deep in the shaded subtree), the
|
|
328
|
+
# canvas must grow with a margin so the plane does not touch the image edge.
|
|
329
|
+
opts = @base_opts.merge(color: "modern", data: "[S [A x] [%B [C #\\+one\\ \\+two]]]")
|
|
330
|
+
svg = RSyntaxTree::RSGenerator.new(opts).draw_svg
|
|
331
|
+
|
|
332
|
+
minx, miny, vbw, vbh = svg[/viewBox="([^"]*)"/, 1].split(",").map(&:to_f)
|
|
333
|
+
shade = svg[/<rect[^>]*fill-opacity[^>]*>/]
|
|
334
|
+
refute_nil shade
|
|
335
|
+
rx = shade[/\bx='([\-0-9.]+)'/, 1].to_f
|
|
336
|
+
ry = shade[/\by='([\-0-9.]+)'/, 1].to_f
|
|
337
|
+
rw = shade[/width='([\-0-9.]+)'/, 1].to_f
|
|
338
|
+
rh = shade[/height='([\-0-9.]+)'/, 1].to_f
|
|
339
|
+
|
|
340
|
+
bottom_margin = (miny + vbh) - (ry + rh)
|
|
341
|
+
right_margin = (minx + vbw) - (rx + rw)
|
|
342
|
+
assert bottom_margin > 8, "Region must keep a bottom margin from the canvas edge (got #{bottom_margin.round(1)})"
|
|
343
|
+
assert right_margin > 8, "Region must keep a right margin from the canvas edge (got #{right_margin.round(1)})"
|
|
344
|
+
end
|
|
345
|
+
|
|
325
346
|
def test_smart_apostrophe_in_label
|
|
326
347
|
# A straight ASCII apostrophe (U+0027) in a label is rendered as a
|
|
327
348
|
# typographic apostrophe (U+2019) for smarter typography (e.g. X-bar "T'").
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rsyntaxtree
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.6.
|
|
4
|
+
version: 1.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yoichiro Hasebe
|
|
@@ -210,6 +210,7 @@ files:
|
|
|
210
210
|
- docs/_examples/062.md
|
|
211
211
|
- docs/_examples/063.md
|
|
212
212
|
- docs/_examples/064.md
|
|
213
|
+
- docs/_examples/065.md
|
|
213
214
|
- docs/_includes/box_and_circle_table.html
|
|
214
215
|
- docs/_includes/escape_char_table.html
|
|
215
216
|
- docs/_includes/social_media_links.html
|
|
@@ -280,6 +281,7 @@ files:
|
|
|
280
281
|
- docs/assets/img/062.png
|
|
281
282
|
- docs/assets/img/063.png
|
|
282
283
|
- docs/assets/img/064.png
|
|
284
|
+
- docs/assets/img/065.png
|
|
283
285
|
- docs/assets/img/elements/arrow_both.png
|
|
284
286
|
- docs/assets/img/elements/arrow_both_bold.png
|
|
285
287
|
- docs/assets/img/elements/arrow_left.png
|
|
@@ -367,6 +369,7 @@ files:
|
|
|
367
369
|
- docs/assets/svg/062.svg
|
|
368
370
|
- docs/assets/svg/063.svg
|
|
369
371
|
- docs/assets/svg/064.svg
|
|
372
|
+
- docs/assets/svg/065.svg
|
|
370
373
|
- docs/documentation.md
|
|
371
374
|
- docs/documentation_ja.md
|
|
372
375
|
- docs/examples.html
|