rsyntaxtree 1.0.8 → 1.1.0
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/.rubocop.yml +77 -0
- data/.solargraph.yml +22 -0
- data/.tags +211 -10
- data/Gemfile +10 -5
- data/README.md +3 -2
- data/Rakefile +3 -1
- data/bin/rsyntaxtree +42 -50
- data/docs/Gemfile +3 -1
- data/docs/_layouts/default.html +1 -1
- data/lib/rsyntaxtree/base_graph.rb +260 -264
- data/lib/rsyntaxtree/element.rb +167 -179
- data/lib/rsyntaxtree/elementlist.rb +105 -124
- data/lib/rsyntaxtree/markup_parser.rb +82 -93
- data/lib/rsyntaxtree/string_parser.rb +221 -237
- data/lib/rsyntaxtree/svg_graph.rb +158 -197
- data/lib/rsyntaxtree/utils.rb +59 -63
- data/lib/rsyntaxtree/version.rb +3 -2
- data/lib/rsyntaxtree.rb +174 -177
- data/rsyntaxtree.gemspec +10 -10
- data/test/markup_parser_test.rb +3 -2
- metadata +23 -21
@@ -1,41 +1,41 @@
|
|
1
|
-
|
2
|
-
# -*- coding: utf-8 -*-
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
#==========================
|
5
4
|
# svg_graph.rb
|
6
5
|
#==========================
|
7
6
|
#
|
8
7
|
# Parses an element list into an SVG tree.
|
9
|
-
# Copyright (c) 2007-
|
8
|
+
# Copyright (c) 2007-2023 Yoichiro Hasebe <yohasebe@gmail.com>
|
10
9
|
|
11
10
|
require "tempfile"
|
12
|
-
|
13
|
-
|
11
|
+
require_relative 'base_graph'
|
12
|
+
require_relative 'utils'
|
14
13
|
|
15
14
|
module RSyntaxTree
|
16
15
|
class SVGGraph < BaseGraph
|
17
16
|
attr_accessor :width, :height
|
18
17
|
|
19
|
-
def initialize(element_list, params)
|
18
|
+
def initialize(element_list, params, global)
|
20
19
|
@height = 0
|
21
20
|
@width = 0
|
22
21
|
@extra_lines = []
|
23
|
-
@fontset
|
24
|
-
@fontsize
|
22
|
+
@fontset = params[:fontset]
|
23
|
+
@fontsize = params[:fontsize]
|
25
24
|
@transparent = params[:transparent]
|
26
25
|
@color = params[:color]
|
27
26
|
@fontstyle = params[:fontstyle]
|
28
27
|
@margin = params[:margin].to_i
|
29
28
|
@polyline = params[:polyline]
|
30
|
-
@line_styles
|
31
|
-
@polyline_styles
|
29
|
+
@line_styles = "<line style='stroke:black; stroke-width:#{FONT_SCALING};' x1='X1' y1='Y1' x2='X2' y2='Y2' />\n"
|
30
|
+
@polyline_styles = "<polyline style='stroke:black; stroke-width:#{FONT_SCALING}; fill:none;'
|
32
31
|
points='CHIX CHIY MIDX1 MIDY1 MIDX2 MIDY2 PARX PARY' />\n"
|
33
|
-
@polygon_styles
|
34
|
-
@text_styles
|
35
|
-
@tree_data
|
32
|
+
@polygon_styles = "<polygon style='fill: none; stroke: black; stroke-width:#{FONT_SCALING};' points='X1 Y1 X2 Y2 X3 Y3' />\n"
|
33
|
+
@text_styles = "<text white-space='pre' alignment-baseline='text-top' style='fill: COLOR; font-size: fontsize' x='X_VALUE' y='Y_VALUE'>CONTENT</text>\n"
|
34
|
+
@tree_data = String.new
|
36
35
|
@visited_x = {}
|
37
36
|
@visited_y = {}
|
38
|
-
|
37
|
+
@global = global
|
38
|
+
super(element_list, params, global)
|
39
39
|
end
|
40
40
|
|
41
41
|
def svg_data
|
@@ -49,32 +49,32 @@ module RSyntaxTree
|
|
49
49
|
y2 = @height + @margin
|
50
50
|
extra_lines = @extra_lines.join("\n")
|
51
51
|
|
52
|
-
as2
|
52
|
+
as2 = @global[:h_gap_between_nodes] / 2 * 0.8
|
53
53
|
as = as2 / 2
|
54
54
|
|
55
|
-
header
|
56
|
-
<?xml version="1.0" standalone="no"?>
|
57
|
-
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
rect
|
76
|
-
<rect x="#{x1}" y="#{y1}" width="#{x2}" height="#{y2}" stroke="none" fill="white" />"
|
77
|
-
|
55
|
+
header = <<~HDR
|
56
|
+
<?xml version="1.0" standalone="no"?>
|
57
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
58
|
+
<svg width="#{@width}" height="#{@height}" viewBox="#{x1}, #{y1}, #{x2}, #{y2}" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
59
|
+
<defs>
|
60
|
+
<marker id="arrow" markerUnits="strokeWidth" markerWidth="#{as2}" markerHeight="#{as2}" viewBox="0 0 #{as2} #{as2}" refX="#{as}" refY="0">
|
61
|
+
<polyline fill="none" stroke="#{@col_path}" stroke-width="1" points="0,#{as2},#{as},0,#{as2},#{as2}" />
|
62
|
+
</marker>
|
63
|
+
<pattern id="hatchBlack" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
64
|
+
<line x1="0" y="0" x2="0" y2="10" stroke="black" stroke-width="4"></line>
|
65
|
+
</pattern>
|
66
|
+
<pattern id="hatchForNode" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
67
|
+
<line x1="0" y="0" x2="0" y2="10" stroke="#{@col_node}" stroke-width="4"></line>
|
68
|
+
</pattern>
|
69
|
+
<pattern id="hatchForLeaf" x="10" y="10" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
70
|
+
<line x1="0" y="0" x2="0" y2="10" stroke="#{@col_leaf}" stroke-width="4"></line>
|
71
|
+
</pattern>
|
72
|
+
</defs>
|
73
|
+
HDR
|
74
|
+
|
75
|
+
rect = <<~RCT
|
76
|
+
<rect x="#{x1}" y="#{y1}" width="#{x2}" height="#{y2}" stroke="none" fill="white" />"
|
77
|
+
RCT
|
78
78
|
|
79
79
|
footer = "</svg>"
|
80
80
|
|
@@ -86,17 +86,15 @@ EOD
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def draw_a_path(s_x, s_y, t_x, t_y, target_arrow = :none)
|
89
|
-
|
90
|
-
|
91
|
-
y_spacing = $height_connector * 0.65
|
89
|
+
x_spacing = @global[:h_gap_between_nodes] * 1.25
|
90
|
+
y_spacing = @global[:height_connector] * 0.65
|
92
91
|
|
93
92
|
ymax = [s_y, t_y].max
|
94
|
-
if ymax
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
93
|
+
new_y = if ymax < @height
|
94
|
+
@height + y_spacing
|
95
|
+
else
|
96
|
+
ymax + y_spacing
|
97
|
+
end
|
100
98
|
|
101
99
|
if @visited_x[s_x]
|
102
100
|
new_s_x = s_x - x_spacing * @visited_x[s_x]
|
@@ -114,67 +112,64 @@ EOD
|
|
114
112
|
@visited_x[t_x] = 1
|
115
113
|
end
|
116
114
|
|
117
|
-
s_y +=
|
118
|
-
t_y +=
|
119
|
-
new_y +=
|
115
|
+
s_y += @global[:h_gap_between_nodes] / 2
|
116
|
+
t_y += @global[:h_gap_between_nodes] / 2
|
117
|
+
new_y += @global[:h_gap_between_nodes] / 2
|
120
118
|
|
121
119
|
dashed = true if target_arrow == :none
|
122
120
|
|
123
|
-
|
121
|
+
case target_arrow
|
122
|
+
when :single
|
124
123
|
@extra_lines << generate_line(new_s_x, s_y, new_s_x, new_y, @col_path, dashed)
|
125
124
|
@extra_lines << generate_line(new_s_x, new_y, new_t_x, new_y, @col_path, dashed)
|
126
|
-
@extra_lines << generate_line(new_t_x, new_y, new_t_x, t_y, @col_path
|
127
|
-
|
125
|
+
@extra_lines << generate_line(new_t_x, new_y, new_t_x, t_y, @col_path, dashed, true)
|
126
|
+
when :double
|
128
127
|
@extra_lines << generate_line(new_s_x, new_y, new_s_x, s_y, @col_path, dashed, true)
|
129
128
|
@extra_lines << generate_line(new_s_x, new_y, new_t_x, new_y, @col_path, dashed)
|
130
|
-
@extra_lines << generate_line(new_t_x, new_y, new_t_x, t_y, @col_path
|
129
|
+
@extra_lines << generate_line(new_t_x, new_y, new_t_x, t_y, @col_path, dashed, true)
|
131
130
|
else
|
132
131
|
@extra_lines << generate_line(new_s_x, s_y, new_s_x, new_y, @col_path, dashed)
|
133
132
|
@extra_lines << generate_line(new_s_x, new_y, new_t_x, new_y, @col_path, dashed)
|
134
|
-
@extra_lines << generate_line(new_t_x, new_y, new_t_x, t_y, @col_path
|
133
|
+
@extra_lines << generate_line(new_t_x, new_y, new_t_x, t_y, @col_path, dashed)
|
135
134
|
end
|
136
135
|
|
137
136
|
@height = new_y if new_y > @height
|
138
137
|
end
|
139
138
|
|
140
139
|
def draw_element(element)
|
141
|
-
top
|
142
|
-
|
143
|
-
|
144
|
-
bottom = top +$single_line_height
|
145
|
-
right = left + element.content_width
|
146
|
-
|
140
|
+
top = element.vertical_indent
|
141
|
+
left = element.horizontal_indent
|
142
|
+
right = left + element.content_width
|
147
143
|
txt_pos = left + (right - left) / 2
|
148
144
|
|
149
|
-
if
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
145
|
+
col = if element.type == ETYPE_LEAF
|
146
|
+
@col_leaf
|
147
|
+
else
|
148
|
+
@col_node
|
149
|
+
end
|
154
150
|
|
155
151
|
text_data = @text_styles.sub(/COLOR/, col)
|
156
152
|
text_data = text_data.sub(/fontsize/, @fontsize.to_s + "px;")
|
157
153
|
text_x = txt_pos - element.content_width / 2
|
158
|
-
text_y = top +
|
154
|
+
text_y = top + @global[:single_line_height] - @global[:height_connector_to_text]
|
159
155
|
text_data = text_data.sub(/X_VALUE/, text_x.to_s)
|
160
156
|
text_data = text_data.sub(/Y_VALUE/, text_y.to_s)
|
161
|
-
new_text = ""
|
157
|
+
new_text = +""
|
162
158
|
this_x = 0
|
163
159
|
this_y = 0
|
164
|
-
bc = {:
|
160
|
+
bc = { x: text_x - @global[:h_gap_between_nodes] / 2, y: top, width: element.content_width + @global[:h_gap_between_nodes], height: nil }
|
165
161
|
element.content.each_with_index do |l, idx|
|
166
162
|
case l[:type]
|
167
163
|
when :border, :bborder
|
168
164
|
x1 = text_x
|
169
|
-
if idx
|
165
|
+
if idx.zero?
|
170
166
|
text_y -= l[:height]
|
171
|
-
|
167
|
+
else
|
172
168
|
text_y += l[:height]
|
173
169
|
end
|
174
|
-
y1 = text_y -
|
170
|
+
y1 = text_y - @global[:single_line_height] / 8
|
175
171
|
x2 = text_x + element.content_width
|
176
172
|
y2 = y1
|
177
|
-
this_width = x2 - x1
|
178
173
|
case l[:type]
|
179
174
|
when :border
|
180
175
|
stroke_width = FONT_SCALING
|
@@ -192,31 +187,23 @@ EOD
|
|
192
187
|
end
|
193
188
|
this_x = txt_pos - (ewidth / 2)
|
194
189
|
end
|
195
|
-
text_y += l[:elements].map{|e| e[:height]}.max if idx != 0
|
190
|
+
text_y += l[:elements].map { |e| e[:height] }.max if idx != 0
|
196
191
|
|
197
|
-
l[:elements].
|
192
|
+
l[:elements].each do |e|
|
198
193
|
escaped_text = e[:text].gsub('>', '>').gsub('<', '<');
|
199
194
|
decorations = []
|
200
|
-
if e[:decoration].include?(:overline)
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
if e[:decoration].include?(:underline)
|
205
|
-
decorations << "underline"
|
206
|
-
end
|
207
|
-
|
208
|
-
if e[:decoration].include?(:linethrough)
|
209
|
-
decorations << "line-through"
|
210
|
-
end
|
211
|
-
decoration ="text-decoration=\"" + decorations.join(" ") + "\""
|
195
|
+
decorations << "overline" if e[:decoration].include?(:overline)
|
196
|
+
decorations << "underline" if e[:decoration].include?(:underline)
|
197
|
+
decorations << "line-through" if e[:decoration].include?(:linethrough)
|
198
|
+
decoration = "text-decoration=\"" + decorations.join(" ") + "\""
|
212
199
|
|
213
200
|
style = "style=\""
|
214
201
|
if e[:decoration].include?(:small)
|
215
202
|
style += "font-size: #{(SUBSCRIPT_CONST.to_f * 100).to_i}%; "
|
216
|
-
this_y = text_y - ((
|
203
|
+
this_y = text_y - ((@global[:single_x_metrics].height - @global[:single_x_metrics].height * SUBSCRIPT_CONST) / 4) + 2
|
217
204
|
elsif e[:decoration].include?(:superscript)
|
218
205
|
style += "font-size: #{(SUBSCRIPT_CONST.to_f * 100).to_i}%; "
|
219
|
-
this_y = text_y - (
|
206
|
+
this_y = text_y - (@global[:single_x_metrics].height / 4) + 1
|
220
207
|
elsif e[:decoration].include?(:subscript)
|
221
208
|
style += "font-size: #{(SUBSCRIPT_CONST.to_f * 100).to_i}%; "
|
222
209
|
this_y = text_y + 4
|
@@ -224,72 +211,59 @@ EOD
|
|
224
211
|
this_y = text_y
|
225
212
|
end
|
226
213
|
|
227
|
-
if e[:decoration].include?(:bold) || e[:decoration].include?(:bolditalic)
|
228
|
-
|
229
|
-
end
|
230
|
-
|
231
|
-
if e[:decoration].include?(:italic) || e[:decoration].include?(:bolditalic)
|
232
|
-
style += "font-style: italic; "
|
233
|
-
end
|
234
|
-
|
214
|
+
style += "font-weight: bold; " if e[:decoration].include?(:bold) || e[:decoration].include?(:bolditalic)
|
215
|
+
style += "font-style: italic; " if e[:decoration].include?(:italic) || e[:decoration].include?(:bolditalic)
|
235
216
|
style += "\""
|
236
217
|
|
237
218
|
case @fontstyle
|
238
219
|
when /(?:cjk)/
|
239
220
|
fontstyle = "'WenQuanYi Zen Hei', 'Noto Sans', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif"
|
240
221
|
when /(?:sans)/
|
241
|
-
if e[:cjk]
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
222
|
+
fontstyle = if e[:cjk]
|
223
|
+
"'Noto Sans JP', 'Noto Sans', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif"
|
224
|
+
else
|
225
|
+
"'Noto Sans', 'Noto Sans JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', sans-serif"
|
226
|
+
end
|
246
227
|
when /(?:serif)/
|
247
|
-
if e[:cjk]
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
228
|
+
fontstyle = if e[:cjk]
|
229
|
+
"'Noto Serif JP', 'Noto Serif', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif"
|
230
|
+
else
|
231
|
+
"'Noto Serif', 'Noto Serif JP', OpenMoji, 'OpenMoji Color', 'OpenMoji Black', serif"
|
232
|
+
end
|
252
233
|
end
|
253
234
|
|
254
235
|
if e[:decoration].include?(:box) || e[:decoration].include?(:circle) || e[:decoration].include?(:bar)
|
255
236
|
enc_height = e[:height]
|
256
237
|
enc_y = this_y - e[:height] * 0.8 + FONT_SCALING
|
257
|
-
|
258
|
-
|
259
|
-
enc_width = e[:width]
|
260
|
-
enc_x = this_x
|
261
|
-
else
|
262
|
-
enc_width = e[:width]
|
263
|
-
enc_x = this_x
|
264
|
-
end
|
238
|
+
enc_width = e[:width]
|
239
|
+
enc_x = this_x
|
265
240
|
|
266
241
|
if e[:decoration].include?(:hatched)
|
267
242
|
case element.type
|
268
243
|
when ETYPE_LEAF
|
269
|
-
if @color
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
244
|
+
fill = if @color
|
245
|
+
"url(#hatchForLeaf)"
|
246
|
+
else
|
247
|
+
"url(#hatchBlack)"
|
248
|
+
end
|
274
249
|
when ETYPE_NODE
|
275
|
-
if @color
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
250
|
+
fill = if @color
|
251
|
+
"url(#hatchForNode)"
|
252
|
+
else
|
253
|
+
"url(#hatchBlack)"
|
254
|
+
end
|
280
255
|
end
|
281
256
|
else
|
282
257
|
fill = "none"
|
283
258
|
end
|
284
259
|
|
285
260
|
enc = nil
|
286
|
-
bar = nil
|
287
261
|
|
288
|
-
if e[:decoration].include?(:bstroke)
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
262
|
+
stroke_width = if e[:decoration].include?(:bstroke)
|
263
|
+
FONT_SCALING * 2.5
|
264
|
+
else
|
265
|
+
FONT_SCALING
|
266
|
+
end
|
293
267
|
|
294
268
|
if e[:decoration].include?(:box)
|
295
269
|
enc = "<rect style='stroke: #{col}; stroke-width:#{stroke_width};'
|
@@ -319,25 +293,22 @@ EOD
|
|
319
293
|
r_arrowhead = "<polyline stroke-linejoin='bevel' fill='none' stroke='#{col}' stroke-width='#{stroke_width}' points='#{x2 - ar_hwidth},#{y2 - ar_hwidth / 2} #{x2},#{y2} #{x2 - ar_hwidth},#{y2 + ar_hwidth / 2}' />\n"
|
320
294
|
@extra_lines << r_arrowhead
|
321
295
|
end
|
322
|
-
|
323
|
-
|
324
296
|
end
|
325
297
|
|
326
298
|
@extra_lines << enc if enc
|
327
299
|
|
328
|
-
if e[:text].size == 1
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
300
|
+
this_x += if e[:text].size == 1
|
301
|
+
(e[:height] - e[:content_width]) / 2
|
302
|
+
else
|
303
|
+
@global[:width_half_x] / 2
|
304
|
+
end
|
305
|
+
|
333
306
|
new_text << set_tspan(this_x, this_y, style, decoration, fontstyle, escaped_text)
|
334
|
-
if e[:text].size == 1
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
this_x += $width_half_X / 2
|
340
|
-
end
|
307
|
+
this_x += if e[:text].size == 1
|
308
|
+
e[:content_width] + (e[:height] - e[:content_width]) / 2
|
309
|
+
else
|
310
|
+
e[:content_width] + @global[:width_half_x] / 2
|
311
|
+
end
|
341
312
|
|
342
313
|
elsif e[:decoration].include?(:whitespace)
|
343
314
|
this_x += e[:width]
|
@@ -346,26 +317,26 @@ EOD
|
|
346
317
|
new_text << set_tspan(this_x, this_y, style, decoration, fontstyle, escaped_text)
|
347
318
|
this_x += e[:width]
|
348
319
|
end
|
349
|
-
|
350
320
|
end
|
351
321
|
end
|
352
322
|
@height = text_y if text_y > @height
|
353
323
|
end
|
354
|
-
bc[:y] = bc[:y] +
|
355
|
-
bc[:height] = text_y - bc[:y] +
|
356
|
-
|
357
|
-
|
324
|
+
bc[:y] = bc[:y] + @global[:height_connector_to_text] * 3 / 4
|
325
|
+
bc[:height] = text_y - bc[:y] + @global[:height_connector_to_text]
|
326
|
+
case element.enclosure
|
327
|
+
when :brackets
|
328
|
+
@extra_lines << generate_line(bc[:x], bc[:y], bc[:x] + @global[:h_gap_between_nodes] / 2, bc[:y], col)
|
358
329
|
@extra_lines << generate_line(bc[:x], bc[:y], bc[:x], bc[:y] + bc[:height], col)
|
359
|
-
@extra_lines << generate_line(bc[:x], bc[:y] + bc[:height], bc[:x] +
|
360
|
-
@extra_lines << generate_line(bc[:x] + bc[:width], bc[:y], bc[:x] + bc[:width] -
|
330
|
+
@extra_lines << generate_line(bc[:x], bc[:y] + bc[:height], bc[:x] + @global[:h_gap_between_nodes] / 2, bc[:y] + bc[:height], col)
|
331
|
+
@extra_lines << generate_line(bc[:x] + bc[:width], bc[:y], bc[:x] + bc[:width] - @global[:h_gap_between_nodes] / 2, bc[:y], col)
|
361
332
|
@extra_lines << generate_line(bc[:x] + bc[:width], bc[:y], bc[:x] + bc[:width], bc[:y] + bc[:height], col)
|
362
|
-
@extra_lines << generate_line(bc[:x] + bc[:width], bc[:y] + bc[:height], bc[:x] + bc[:width] -
|
363
|
-
|
333
|
+
@extra_lines << generate_line(bc[:x] + bc[:width], bc[:y] + bc[:height], bc[:x] + bc[:width] - @global[:h_gap_between_nodes] / 2, bc[:y] + bc[:height], col)
|
334
|
+
when :rectangle
|
364
335
|
@extra_lines << generate_line(bc[:x], bc[:y], bc[:x] + bc[:width], bc[:y], col)
|
365
336
|
@extra_lines << generate_line(bc[:x], bc[:y], bc[:x], bc[:y] + bc[:height], col)
|
366
337
|
@extra_lines << generate_line(bc[:x] + bc[:width], bc[:y], bc[:x] + bc[:width], bc[:y] + bc[:height], col)
|
367
338
|
@extra_lines << generate_line(bc[:x], bc[:y] + bc[:height], bc[:x] + bc[:width], bc[:y] + bc[:height], col)
|
368
|
-
|
339
|
+
when :brectangle
|
369
340
|
@extra_lines << generate_line(bc[:x], bc[:y], bc[:x] + bc[:width], bc[:y], col, false, false, 2)
|
370
341
|
@extra_lines << generate_line(bc[:x], bc[:y], bc[:x], bc[:y] + bc[:height], col, false, false, 2)
|
371
342
|
@extra_lines << generate_line(bc[:x] + bc[:width], bc[:y], bc[:x] + bc[:width], bc[:y] + bc[:height], col, false, false, 2)
|
@@ -384,9 +355,7 @@ EOD
|
|
384
355
|
"<tspan x='#{this_x}' y='#{this_y}' #{style} #{decoration} font-family=\"#{fontstyle}\">#{text}</tspan>\n"
|
385
356
|
end
|
386
357
|
|
387
|
-
|
388
358
|
def draw_paths
|
389
|
-
rockbottom = 0
|
390
359
|
path_pool_target = {}
|
391
360
|
path_pool_other = {}
|
392
361
|
path_pool_source = {}
|
@@ -397,7 +366,7 @@ EOD
|
|
397
366
|
elist.each do |element|
|
398
367
|
x1 = element.horizontal_indent + element.content_width / 2
|
399
368
|
y1 = element.vertical_indent + element.content_height
|
400
|
-
y1 +=
|
369
|
+
y1 += @global[:height_connector_to_text] if element.enclosure != :none
|
401
370
|
et = element.path
|
402
371
|
et.each do |tr|
|
403
372
|
if /\A>(\d+)\z/ =~ tr
|
@@ -417,28 +386,24 @@ EOD
|
|
417
386
|
path_pool_source[tr] = [x1, y1]
|
418
387
|
end
|
419
388
|
path_flags << tr
|
420
|
-
if path_flags.tally.any?{|
|
421
|
-
raise RSTError, "Error: input text contains a path having more than two ends:\n > #{tr}"
|
422
|
-
end
|
389
|
+
raise RSTError, "Error: input text contains a path having more than two ends:\n > #{tr}" if path_flags.tally.any? { |_k, v| v > 2 }
|
423
390
|
end
|
424
391
|
end
|
425
392
|
|
426
393
|
path_flags.tally.each do |k, v|
|
427
|
-
if v == 1
|
428
|
-
raise RSTError, "Error: input text contains a path having only one end:\n > #{k}"
|
429
|
-
end
|
394
|
+
raise RSTError, "Error: input text contains a path having only one end:\n > #{k}" if v == 1
|
430
395
|
end
|
431
396
|
|
432
397
|
paths = []
|
433
398
|
path_pool_source.each do |k, v|
|
434
399
|
path_flags.delete(k)
|
435
|
-
if targets = path_pool_target[k]
|
400
|
+
if (targets = path_pool_target[k])
|
436
401
|
targets.each do |t|
|
437
|
-
paths << {x1: v[0], y1: v[1], x2: t[0], y2: t[1], arrow: :single}
|
402
|
+
paths << { x1: v[0], y1: v[1], x2: t[0], y2: t[1], arrow: :single }
|
438
403
|
end
|
439
|
-
elsif others = path_pool_other[k]
|
404
|
+
elsif (others = path_pool_other[k])
|
440
405
|
others.each do |t|
|
441
|
-
paths << {x1: v[0], y1: v[1], x2: t[0], y2: t[1], arrow: :none}
|
406
|
+
paths << { x1: v[0], y1: v[1], x2: t[0], y2: t[1], arrow: :none }
|
442
407
|
end
|
443
408
|
end
|
444
409
|
end
|
@@ -447,13 +412,13 @@ EOD
|
|
447
412
|
targets = path_pool_target[k]
|
448
413
|
fst = targets.shift
|
449
414
|
targets.each do |t|
|
450
|
-
paths << {x1: fst[0], y1: fst[1], x2: t[0], y2: t[1], arrow: :double}
|
415
|
+
paths << { x1: fst[0], y1: fst[1], x2: t[0], y2: t[1], arrow: :double }
|
451
416
|
end
|
452
417
|
end
|
453
418
|
|
454
419
|
paths.each do |t|
|
455
|
-
draw_a_path(t[:x1], t[:y1] +
|
456
|
-
t[:x2], t[:y2] +
|
420
|
+
draw_a_path(t[:x1], t[:y1] + @global[:height_connector_to_text] / 2,
|
421
|
+
t[:x2], t[:y2] + @global[:height_connector_to_text] / 2,
|
457
422
|
t[:arrow])
|
458
423
|
end
|
459
424
|
|
@@ -461,11 +426,11 @@ EOD
|
|
461
426
|
end
|
462
427
|
|
463
428
|
def generate_line(x1, y1, x2, y2, col, dashed = false, arrow = false, stroke_width = 1)
|
464
|
-
if arrow
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
429
|
+
string = if arrow
|
430
|
+
"marker-end='url(#arrow)' "
|
431
|
+
else
|
432
|
+
""
|
433
|
+
end
|
469
434
|
dasharray = dashed ? "stroke-dasharray='8 8'" : ""
|
470
435
|
swidth = FONT_SCALING * stroke_width
|
471
436
|
|
@@ -474,36 +439,34 @@ EOD
|
|
474
439
|
|
475
440
|
# Draw a line between child/parent elements
|
476
441
|
def line_to_parent(parent, child)
|
477
|
-
if
|
478
|
-
return
|
479
|
-
end
|
442
|
+
return if child.horizontal_indent.zero?
|
480
443
|
|
481
444
|
if @polyline
|
482
445
|
chi_x = child.horizontal_indent + child.content_width / 2
|
483
|
-
chi_y = child.vertical_indent +
|
446
|
+
chi_y = child.vertical_indent + @global[:height_connector_to_text] / 2
|
484
447
|
|
485
448
|
par_x = parent.horizontal_indent + parent.content_width / 2
|
486
|
-
par_y = parent.vertical_indent + parent.content_height +
|
449
|
+
par_y = parent.vertical_indent + parent.content_height + @global[:height_connector_to_text]
|
487
450
|
|
488
451
|
mid_x1 = chi_x
|
489
|
-
mid_y1 = par_y
|
452
|
+
mid_y1 = par_y + (chi_y - par_y) / 2
|
490
453
|
|
491
454
|
mid_x2 = par_x
|
492
455
|
mid_y2 = mid_y1
|
493
456
|
|
494
457
|
@tree_data += @polyline_styles.sub(/CHIX/, chi_x.to_s)
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
458
|
+
.sub(/CHIY/, chi_y.to_s)
|
459
|
+
.sub(/MIDX1/, mid_x1.to_s)
|
460
|
+
.sub(/MIDY1/, mid_y1.to_s)
|
461
|
+
.sub(/MIDX2/, mid_x2.to_s)
|
462
|
+
.sub(/MIDY2/, mid_y2.to_s)
|
463
|
+
.sub(/PARX/, par_x.to_s)
|
464
|
+
.sub(/PARY/, par_y.to_s)
|
502
465
|
else
|
503
466
|
x1 = child.horizontal_indent + child.content_width / 2
|
504
|
-
y1 = child.vertical_indent +
|
467
|
+
y1 = child.vertical_indent + @global[:height_connector_to_text] / 2
|
505
468
|
x2 = parent.horizontal_indent + parent.content_width / 2
|
506
|
-
y2 = parent.vertical_indent + parent.content_height +
|
469
|
+
y2 = parent.vertical_indent + parent.content_height + @global[:height_connector_to_text]
|
507
470
|
|
508
471
|
line_data = @line_styles.sub(/X1/, x1.to_s)
|
509
472
|
line_data = line_data.sub(/Y1/, y1.to_s)
|
@@ -514,16 +477,14 @@ EOD
|
|
514
477
|
|
515
478
|
# Draw a triangle between child/parent elements
|
516
479
|
def triangle_to_parent(parent, child)
|
517
|
-
if
|
518
|
-
return
|
519
|
-
end
|
480
|
+
return if child.horizontal_indent.zero?
|
520
481
|
|
521
482
|
x1 = child.horizontal_indent
|
522
|
-
y1 = child.vertical_indent +
|
483
|
+
y1 = child.vertical_indent + @global[:height_connector_to_text] / 2
|
523
484
|
x2 = child.horizontal_indent + child.content_width
|
524
|
-
y2 = child.vertical_indent +
|
485
|
+
y2 = child.vertical_indent + @global[:height_connector_to_text] / 2
|
525
486
|
x3 = parent.horizontal_indent + parent.content_width / 2
|
526
|
-
y3 = parent.vertical_indent + parent.content_height +
|
487
|
+
y3 = parent.vertical_indent + parent.content_height + @global[:height_connector_to_text]
|
527
488
|
|
528
489
|
polygon_data = @polygon_styles.sub(/X1/, x1.to_s)
|
529
490
|
polygon_data = polygon_data.sub(/Y1/, y1.to_s)
|