rsyntaxtree 0.8.5 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9fb3b6ae45edfeea2b1b280bfc432d7f3c669b235139638fba59c633b8326e70
4
- data.tar.gz: 7c7d7e76f03a70eea5514c6d8d9bae87a4d05f78ee4ff9c63785da0058a38b9f
3
+ metadata.gz: e72c92c9014be74d57f4406e6f1e143b3f9e8dffc32f48ecfebd4a0adbf6a4e2
4
+ data.tar.gz: 4efd624a82d601829b48ed8fedec7265d65b5bc353deb5356ac37a6eefa0a7da
5
5
  SHA512:
6
- metadata.gz: 8f4754c519c2687b25df411c9a5025cd93363dc9bcb20cf3c7ef3281ac01fe05cf7414d35b0eb565ea00c7b3aac8d83fb4a1bb016428f1ddcb13cde08e197de3
7
- data.tar.gz: 9d3c8fa5126ca404f4d32ebc6b8af4d3feac4252d729acca6048501dea39e377ea597c8a7d406f98e46d8bb3fa22b43d3b5243678c8ae70e9fc437bf61cf2601
6
+ metadata.gz: b26b81c9ebfec90f73e66cf562ad664d8081291fd869c4e9913220ab24e90fe81f081c729abf35f32af4141084ae26e8c29af97cb1a1e0e5be165900d358cc45
7
+ data.tar.gz: 7f08d17d331d2510357bb586d5c70190418c134654d1fbdac6c2a0b7b0c2716caabf8762ed231eabf627e59d5b07cc77b3e40d46e2ce1f78f90852122a166a32
data/bin/rsyntaxtree CHANGED
@@ -37,6 +37,8 @@ EOS
37
37
  :default => "on"
38
38
  opt :autosub, "Put subscript numbers to nodes: on or off",
39
39
  :default => "off"
40
+ opt :transparent, "Make background transparent: on or off",
41
+ :default => "off"
40
42
  end
41
43
 
42
44
  Optimist::die :outdir, "must be an exsting directory path" unless FileTest::directory?(opts[:outdir])
@@ -48,8 +50,9 @@ Optimist::die :fontsize, "must be in the range of 8-26" unless opts[:fontsize] >
48
50
  Optimist::die :color, "must be either on or off" unless /\A(on|off)\z/ =~ opts[:color]
49
51
  Optimist::die :symmetrize, "must be either on or off" unless /\A(on|off)\z/ =~ opts[:symmetrize]
50
52
  Optimist::die :autosub, "must be either on or off" unless /\A(on|off)\z/ =~ opts[:autosub]
51
- Optimist::die :margin, "must be in the range of 1-5" if opts[:margin] < 1 || opts[:margin] > 5
53
+ Optimist::die :margin, "must be in the range of 0-5" if opts[:margin] < 1 || opts[:margin] > 5
52
54
  Optimist::die :vheight, "must be in the range of 0.5-5.0" if opts[:vheight] < 0.5 || opts[:vheight] > 5.0
55
+ Optimist::die :transparent, "must be either on or off" unless /\A(on|off)\z/ =~ opts[:transparent]
53
56
 
54
57
  string_opts = {}
55
58
  opts.each do |key, value|
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -23,12 +23,12 @@ class Element
23
23
  @level = level # Element level in the tree (0=top etc...)
24
24
  @width = 0 # Width of the element in pixels
25
25
  @indent = 0 # Drawing offset
26
- # content = content.strip
27
- if /\A.+\^\z/ =~ content.strip
26
+ content = content.strip
27
+ if /\A.+\^\z/m =~ content
28
28
  @content = content.gsub("^"){""} # The actual element content
29
29
  @triangle = true # draw triangle instead of stright bar when in auto mode
30
30
  else
31
- @content = content.gsub("^"){""} # The actual element content
31
+ @content = content.gsub("^"){""}.strip # The actual element content
32
32
  @triangle = false # draw triangle instead of stright bar when in auto mode
33
33
  end
34
34
  # workaround to save "[A [B [C] [D] ] [E [F] [G [H] [J] ] ] ]"
@@ -23,7 +23,7 @@ class ErrorMessage
23
23
  @filename = filename
24
24
  @format = format
25
25
 
26
- metrics = img_get_txt_metrics(text, font, font_size, true)
26
+ metrics = img_get_txt_metrics(text, font, font_size, NoDecoration, true)
27
27
 
28
28
  @im = Image.new(metrics.width, metrics.height)
29
29
  @gc = Draw.new
@@ -32,8 +32,8 @@ class Graph
32
32
  # Calculate image dimensions
33
33
  @e_height = font_size + @m[:e_padd] * 2
34
34
  h = @e_list.get_level_height
35
- w = calc_level_width(0)
36
- @width = w + @m[:b_side] * 2
35
+ w = calc_level_width(0)
36
+ @width = w
37
37
  @height = h * @e_height + (h-1) * (@m[:v_space] + font_size) + @m[:b_topbot] * 2
38
38
 
39
39
  # Initialize the image and colors
@@ -58,7 +58,6 @@ class Graph
58
58
 
59
59
  def img_get_txt_metrics(text, font, font_size, multiline)
60
60
 
61
- # background = Image.new(500, 250)
62
61
  background = Image.new(1, 1)
63
62
 
64
63
  gc = Draw.new
@@ -67,6 +66,9 @@ class Graph
67
66
  gc.pointsize = font_size
68
67
  gc.gravity = CenterGravity
69
68
  gc.stroke = 'none'
69
+ gc.kerning = 0
70
+ gc.interline_spacing = 0
71
+ gc.interword_spacing = 0
70
72
  end
71
73
 
72
74
  if multiline
@@ -82,18 +84,19 @@ class Graph
82
84
  # for all child elements.
83
85
  def calc_element_width(e)
84
86
  w = 0
87
+ content = e.content.gsub("<>", " ")
85
88
 
86
89
  children = @e_list.get_children(e.id)
87
90
 
88
91
  if(children.length == 0)
89
- w = img_get_txt_width(e.content, @font, @font_size) + @font_size
92
+ w = img_get_txt_width(content, @font, @font_size) + @font_size
90
93
  else
91
94
  children.each do |child|
92
95
  child_e = @e_list.get_id(child)
93
96
  w += calc_element_width(child_e)
94
97
  end
95
98
 
96
- tw = img_get_txt_width(e.content, @font, @font_size) + @font_size
99
+ tw = img_get_txt_width(content, @font, @font_size) + @font_size
97
100
  if(tw > w)
98
101
  fix_child_size(e.id, w, tw)
99
102
  w = tw
@@ -110,9 +113,10 @@ class Graph
110
113
  e = @e_list.get_first
111
114
  while e
112
115
  if(e.level == level)
113
- w += calc_element_width(e)
116
+ x = calc_element_width(e)
117
+ w += x
114
118
  end
115
- e = @e_list.get_next
119
+ e = @e_list.get_next
116
120
  end
117
121
  return w
118
122
  end
@@ -168,30 +172,31 @@ class Graph
168
172
  if(j.parent != 0 )
169
173
  words = j.content.split(" ")
170
174
  unless @leafstyle == "nothing" && ETYPE_LEAF == j.type
171
- if (@leafstyle == "triangle" && ETYPE_LEAF == j.type && x == parent_indent && words.length > 0)
172
- txt_width = img_get_txt_width(j.content, @font, @font_size)
173
- triangle_to_parent(x, i, cw, txt_width, @symmetrize)
174
- elsif (@leafstyle == "auto" && ETYPE_LEAF == j.type && x == parent_indent)
175
- if words.length > 1 || j.triangle
176
- txt_width = img_get_txt_width(j.content, @font, @font_size)
177
- triangle_to_parent(x, i, cw, txt_width, @symmetrize)
178
- else
179
- line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
180
- end
175
+ if (@leafstyle == "auto" && ETYPE_LEAF == j.type && x == parent_indent)
176
+ if words.length > 1 || j.triangle
177
+ txt_width = img_get_txt_width(j.content, @font, @font_size)
178
+ triangle_to_parent(x, i, cw, txt_width, @symmetrize)
179
+ else
180
+ line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
181
+ end
181
182
  else
182
183
  line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
183
184
  end
184
185
  end
185
186
  end
186
187
  end
187
-
188
188
  x += cw
189
189
  end
190
190
  end
191
191
  end
192
192
  return true if !@symmetrize
193
193
 
194
- @check = []
194
+ elements_to_draw = {}
195
+ triangles_to_draw = []
196
+ lines_to_draw = []
197
+
198
+ lmost = {:level => nil, :value => nil, :type => nil}
199
+ rmost = nil
195
200
  h.times do |i|
196
201
  curlevel = h - i - 1
197
202
  e_arr.each_with_index do |j, idx|
@@ -209,7 +214,7 @@ class Graph
209
214
  right = k.indent + kw / 2 if k.indent + kw / 2 > right
210
215
  end
211
216
 
212
- draw_element(left, curlevel, right - left, j.content, j.type)
217
+ elements_to_draw[j.id] = {:left => left, :curlevel => curlevel, :width => right - left, :content => j.content, :type => j.type}
213
218
  @e_list.set_indent(j.id, left + (right - left) / 2 - tw / 2)
214
219
 
215
220
  children.each do |child|
@@ -223,12 +228,12 @@ class Graph
223
228
  if (@leafstyle == "auto" && ETYPE_LEAF == k.type)
224
229
  if words.length > 1 || k.triangle
225
230
  txt_width = img_get_txt_width(k.content, @font, @font_size)
226
- triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
231
+ triangles_to_draw << {:indent => k.indent, :curlevel => curlevel + 1, :width1 => dw, :width2 => txt_width}
227
232
  else
228
- line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
233
+ lines_to_draw << {:indent1 => k.indent, :curlevel => curlevel + 1, :width1 => dw, :indent2 => j.indent, :width2 => tw}
229
234
  end
230
235
  else
231
- line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
236
+ lines_to_draw << {:indent1 => k.indent, :curlevel => curlevel + 1, :width1 => dw, :indent2 => j.indent, :width2 => tw}
232
237
  end
233
238
  end
234
239
  end
@@ -237,32 +242,46 @@ class Graph
237
242
  elements = e_arr.select do |l|
238
243
  l.level == curlevel && @e_list.get_children(l.id).empty?
239
244
  end
240
- process_terminal(elements, j, curlevel, tw)
245
+
246
+ elements.each.with_index do |l, idx|
247
+ lw = img_get_txt_width(l.content, @font, @font_size)
248
+ left = l.indent
249
+ right = left + lw
250
+ unless elements_to_draw.include? l.id
251
+ elements_to_draw[l.id] = {:left => left, :curlevel => curlevel, :width => right - left, :content => l.content, :type => l.type}
252
+ end
253
+ end
241
254
  end
242
255
  end
256
+
257
+ e_arr.each do |e|
258
+ lpos = e.indent - img_get_txt_width(e.content, @font, @font_size) / 2
259
+ next if lpos > 0
260
+ if !lmost[:value] || lmost[:value] > lpos
261
+ lmost[:level] = e.level
262
+ lmost[:value] = lpos
263
+ lmost[:type] = e
264
+ end
265
+ rpos = e.indent + e.width
266
+ rmost = rpos if !rmost || rmost < rpos
267
+ end
243
268
  end
244
- end
245
269
 
270
+ offset = 0
271
+ if lmost[:level] != h - 1
272
+ offset = lmost[:value] / -2
273
+ new_width = rmost
274
+ @width = new_width + offset
275
+ end
246
276
 
247
- def process_terminal(elements, j, curlevel, tw)
248
- # parent = @e_list.get_id(j.parent)
249
- # return unless parent
250
- # pw = img_get_txt_width(parent.content, @font, @font_size)
251
- # pleft = parent.indent
252
- # pright = pleft + pw
253
-
254
- elements.each.with_index do |l, idx|
255
- lw = img_get_txt_width(l.content, @font, @font_size)
256
- left = l.indent
257
- right = left + lw
258
- # if pw > tw
259
- # left = pleft
260
- # right = pright
261
- # end
262
- unless @check.include? l.id
263
- draw_element(left, curlevel, right - left, l.content, l.type)
264
- @check << l.id
265
- end
277
+ elements_to_draw.each do |k, v|
278
+ draw_element(v[:left] + offset, v[:curlevel], v[:width], v[:content], v[:type])
279
+ end
280
+ triangles_to_draw.each do |v|
281
+ triangle_to_parent(v[:indent] + offset, v[:curlevel], v[:width1], v[:width2])
282
+ end
283
+ lines_to_draw.each do |v|
284
+ line_to_parent(v[:indent1] + offset, v[:curlevel], v[:width1], v[:indent2] + offset, v[:width2])
266
285
  end
267
286
  end
268
287
 
@@ -284,8 +303,9 @@ class Graph
284
303
  return text
285
304
  end
286
305
 
287
- def img_get_txt_height(text, font, font_size, multiline = false)
306
+ def img_get_txt_height(text, font, font_size, multiline = true)
288
307
  metrics = img_get_txt_metrics(text, font, font_size, multiline)
308
+ # y = (metrics.bounds.y2 - metrics.bounds.y1).round
289
309
  y = metrics.height
290
310
  return y
291
311
  end
@@ -171,8 +171,15 @@ class StringParser
171
171
  end
172
172
  when "\\"
173
173
  escape = true
174
- when /[\n\r]/
175
- gottoken = false # same as do nothing
174
+ when "n", " ", "+", "-", "=", "~", "#", "*"
175
+ if escape
176
+ token += "\\#{ch}"
177
+ escape = false
178
+ else
179
+ token += ch
180
+ end
181
+ # when /[\n\r]/
182
+ # gottoken = false # same as do nothing
176
183
  else
177
184
  token += ch
178
185
  escape = false if escape
@@ -18,37 +18,70 @@ require 'graph'
18
18
 
19
19
  class SVGGraph < Graph
20
20
 
21
- def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte, fontstyle, font, font_cjk, font_size)
21
+ def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte, fontstyle, font, font_cjk, font_size, margin, transparent)
22
22
 
23
23
  # Store class-specific parameters
24
24
  @font = multibyte ? font_cjk : font
25
25
  @font_size = font_size
26
+ @transparent = transparent
27
+
26
28
  case fontstyle
27
29
  when /(?:sans|cjk)/
28
- @fontstyle = "sans-serif"
29
- when /(?:serif|math)/
30
- @fontstyle = "serif"
30
+ @fontstyle = "\"'Noto Sans JP', 'Noto Sans', sans-serif\""
31
+ @fontcss = "http://fonts.googleapis.com/earlyaccess/notosansjp.css"
32
+ when /(?:serif)/
33
+ @fontstyle = "\"'Noto Serif JP', 'Noto Serif', serif\""
34
+ @fontcss = "https://fonts.googleapis.com/css?family=Noto+Serif+JP"
35
+ when /(?:math)/
36
+ @fontstyle = "\"Latin Modern Roman', sans-serif\""
37
+ @fontcss = "https://cdn.jsdelivr.net/gh/sugina-dev/latin-modern-web@1.0.1/style/latinmodern-roman.css"
31
38
  end
32
39
 
33
- super(e_list, metrics, symmetrize, color, leafstyle, multibyte, @font, @font_size)
40
+ @margin = margin.to_i
41
+
42
+ super(e_list, metrics, symmetrize, color, leafstyle, multibyte, @fontstyle, @font_size)
34
43
 
35
44
  @line_styles = "<line style='stroke:black; stroke-width:#{FONT_SCALING};' x1='X1' y1='Y1' x2='X2' y2='Y2' />\n"
36
45
  @polygon_styles = "<polygon style='fill: none; stroke: black; stroke-width:#{FONT_SCALING};' points='X1 Y1 X2 Y2 X3 Y3' />\n"
37
- @text_styles = "<text style='fill: COLOR; font-size: FONT_SIZEpx; ST; WA;' x='X_VALUE' y='Y_VALUE' TD font-family='#{@fontstyle}'>CONTENT</text>\n"
46
+ @text_styles = "<text letter-spacing='0' word-spacing='0' kerning='0' style='fill: COLOR; font-size: FONT_SIZE ST WA' x='X_VALUE' y='Y_VALUE' TD font-family=#{@fontstyle}>CONTENT</text>\n"
38
47
  @tree_data = String.new
39
48
  end
40
49
 
50
+ def get_left_most(tree_data)
51
+ xs = @tree_data.scan(/x1?=['"]([^'"]+)['"]/).map{|m| m.first.to_i}
52
+ xs.min
53
+ end
54
+
41
55
  def svg_data
42
56
  parse_list
57
+ lm = get_left_most(@tree_data)
58
+ width = @width - lm + @margin * 2
59
+ height = @height + @margin * 2
60
+
43
61
  header =<<EOD
44
62
  <?xml version="1.0" standalone="no"?>
45
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
63
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
46
64
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
47
- <svg width="#{@width}" height="#{@height}" version="1.1" xmlns="http://www.w3.org/2000/svg">
65
+ <svg width="#{width}" height="#{height}" viewBox="#{-@margin + lm}, -#{@margin}, #{@width - lm + @margin * 2}, #{@height + @margin * 2}" version="1.1" xmlns="http://www.w3.org/2000/svg">
66
+ <defs>
67
+ <style>
68
+ @import url(#{@fontcss});
69
+ </style>
70
+ </defs>
71
+ EOD
72
+
73
+
74
+ rect =<<EOD
75
+ <rect x="#{-@margin + lm}" y="-#{@margin}" width="#{@width - lm + @margin * 2}" height="#{@height + @margin * 2}" stroke="none" fill="white" />"
48
76
  EOD
49
77
 
50
78
  footer = "</svg>"
51
- header + @tree_data + footer
79
+
80
+ if @transparent
81
+ header + @tree_data + footer
82
+ else
83
+ header + rect + @tree_data + footer
84
+ end
52
85
  end
53
86
 
54
87
  # Create a temporary file and returns only its filename
@@ -68,21 +101,21 @@ EOD
68
101
  end
69
102
 
70
103
  :private
71
-
104
+
72
105
  # Add the element into the tree (draw it)
73
106
  def draw_element(x, y, w, string, type)
74
- string = string.sub(/\^\z/){""}
107
+ string = string.sub(/\^\z/){""}
75
108
  # Calculate element dimensions and position
76
109
  if (type == ETYPE_LEAF) and @leafstyle == "nothing"
77
110
  top = row2px(y - 1) + (@font_size * 1.5)
78
- else
111
+ else
79
112
  top = row2px(y)
80
113
  end
81
114
  left = x + @m[:b_side]
82
115
  bottom = top + @e_height
83
116
  right = left + w
84
117
 
85
- # Split the string into the main part and the
118
+ # Split the string into the main part and the
86
119
  # subscript part of the element (if any)
87
120
  parts = string.split("_", 2)
88
121
  if(parts.length > 1 )
@@ -127,11 +160,18 @@ EOD
127
160
  main = $1
128
161
  end
129
162
 
130
- # Calculate text size for the main and the
163
+ # Calculate text size for the main and the
131
164
  # subscript part of the element
132
165
  # symbols for underline/overline removed temporarily
133
166
 
134
- main_width = img_get_txt_width(main, @font, @font_size)
167
+ main_width = 0
168
+ main_height = 0
169
+ main.split(/\\n/).each do |l|
170
+ l_width = img_get_txt_width(l, @font, @font_size)
171
+ main_width = l_width if main_width < l_width
172
+ main_height += img_get_txt_height(l, @font, @font_size)
173
+ end
174
+
135
175
 
136
176
  if sub != ""
137
177
  if /\A\=(.+)\=\z/ =~ sub
@@ -163,9 +203,11 @@ EOD
163
203
  sub_style = ""
164
204
  sub_weight = ""
165
205
  end
206
+ sub_height = img_get_txt_height(sub, @font, @font_size)
166
207
  sub_width = img_get_txt_width(sub.to_s, @font, @sub_size)
167
208
  else
168
209
  sub_width = 0
210
+ sub_height = 0
169
211
  end
170
212
 
171
213
  if /\A#(.+)#\z/ =~ sub
@@ -173,14 +215,13 @@ EOD
173
215
  end
174
216
 
175
217
  # Center text in the element
176
- txt_width = main_width + sub_width
177
- txt_pos = left + (right - left) / 2 - txt_width / 2
218
+ txt_pos = left + (right - left) / 2
178
219
 
179
220
  # Select apropriate color
180
221
  if(type == ETYPE_LEAF)
181
222
  col = @col_leaf
182
223
  else
183
- col = @col_node
224
+ col = @col_node
184
225
  end
185
226
 
186
227
  if(main[0].chr == "<" && main[-1].chr == ">")
@@ -189,29 +230,47 @@ EOD
189
230
 
190
231
  # Draw main text
191
232
  main_data = @text_styles.sub(/COLOR/, col)
192
- main_data = main_data.sub(/FONT_SIZE/, @font_size.to_s)
193
- main_x = txt_pos
194
- main_y = top + @e_height - @m[:e_padd] * 1.5
233
+ main_data = main_data.sub(/FONT_SIZE/, @font_size.to_s + "px;")
234
+ main_x = txt_pos - (main_width + sub_width) / 2
235
+ main_y = top + @e_height - @m[:e_padd]
195
236
  main_data = main_data.sub(/X_VALUE/, main_x.to_s)
196
237
  main_data = main_data.sub(/Y_VALUE/, main_y.to_s)
197
-
238
+ if /\\n/ =~ main
239
+ lines = main.split(/\\n/)
240
+ new_main = ""
241
+ dy = 0
242
+ lines.each_with_index do |l, idx|
243
+ if idx == 0
244
+ dy = 0
245
+ else
246
+ dy = 1
247
+ main_y += img_get_txt_height(l, @font, @font_size)
248
+ end
249
+ this_width = img_get_txt_width(l, @font, @font_size)
250
+ this_x = txt_pos - (this_width + sub_width) / 2
251
+ new_main << "<tspan x='#{this_x}' y='#{main_y}'>#{l}</tspan>"
252
+ @height = main_y if main_y > @height
253
+ end
254
+ main = new_main
255
+ end
198
256
  @tree_data += main_data.sub(/TD/, "text-decoration='#{main_decoration}'")
199
- .sub(/ST/, main_style)
200
- .sub(/WA/, main_weight)
257
+ .sub(/ST/, main_style + ";")
258
+ .sub(/WA/, main_weight + ";")
201
259
  .sub(/CONTENT/, main)
202
260
 
203
261
  # Draw subscript text
204
- sub_data = @text_styles.sub(/COLOR/, col)
205
- sub_data = sub_data.sub(/FONT_SIZE/, @sub_size.to_s)
206
- sub_x = main_x + main_width
207
- sub_y = top + (@e_height - @m[:e_padd] + @sub_size / 10)
208
- if (sub.length > 0 )
209
- sub_data = sub_data.sub(/X_VALUE/, sub_x.ceil.to_s)
210
- sub_data = sub_data.sub(/Y_VALUE/, sub_y.ceil.to_s)
262
+ if sub && sub != ""
263
+ sub_data = @text_styles.sub(/COLOR/, col)
264
+ sub_data = sub_data.sub(/FONT_SIZE/, @sub_size.to_s)
265
+ sub_x = txt_pos + (main_width / 2) - (sub_width / 2)
266
+ sub_y = main_y + sub_height / 6
267
+ sub_data = sub_data.sub(/X_VALUE/, sub_x.to_s)
268
+ sub_data = sub_data.sub(/Y_VALUE/, sub_y.to_s)
211
269
  @tree_data += sub_data.sub(/TD/, "text-decoration='#{sub_decoration}'")
212
270
  .sub(/ST/, sub_style)
213
271
  .sub(/WA/, sub_weight)
214
- .sub(/CONTENT/, sub)
272
+ .sub(/CONTENT/, sub)
273
+ @height += sub_height / 4
215
274
  end
216
275
  end
217
276
 
@@ -227,10 +286,10 @@ EOD
227
286
  toBot = (row2px(fromY - 1 ) + @e_height)
228
287
  toLeft = (toX + toW / 2 + @m[:b_side])
229
288
 
230
- line_data = @line_styles.sub(/X1/, fromLeft.ceil.to_s)
231
- line_data = line_data.sub(/Y1/, fromTop.ceil.to_s)
232
- line_data = line_data.sub(/X2/, toLeft.ceil.to_s)
233
- @tree_data += line_data.sub(/Y2/, toBot.ceil.to_s)
289
+ line_data = @line_styles.sub(/X1/, fromLeft.to_s)
290
+ line_data = line_data.sub(/Y1/, fromTop.to_s)
291
+ line_data = line_data.sub(/X2/, toLeft.to_s)
292
+ @tree_data += line_data.sub(/Y2/, toBot.to_s)
234
293
 
235
294
  end
236
295
 
@@ -243,9 +302,9 @@ EOD
243
302
  toX = fromX
244
303
  fromCenter = (fromX + fromW / 2 + @m[:b_side])
245
304
 
246
- fromTop = row2px(fromY).ceil
247
- fromLeft1 = (fromCenter + textW / 2).ceil
248
- fromLeft2 = (fromCenter - textW / 2).ceil
305
+ fromTop = row2px(fromY)
306
+ fromLeft1 = (fromCenter + textW / 2)
307
+ fromLeft2 = (fromCenter - textW / 2)
249
308
  toBot = (row2px(fromY - 1) + @e_height)
250
309
 
251
310
  if symmetrize
@@ -254,12 +313,12 @@ EOD
254
313
  toLeft = (toX + textW / 2 + @m[:b_side] * 3)
255
314
  end
256
315
 
257
- polygon_data = @polygon_styles.sub(/X1/, fromLeft1.ceil.to_s)
258
- polygon_data = polygon_data.sub(/Y1/, fromTop.ceil.to_s)
259
- polygon_data = polygon_data.sub(/X2/, fromLeft2.ceil.to_s)
260
- polygon_data = polygon_data.sub(/Y2/, fromTop.ceil.to_s)
261
- polygon_data = polygon_data.sub(/X3/, toLeft.ceil.to_s)
262
- @tree_data += polygon_data.sub(/Y3/, toBot.ceil.to_s)
316
+ polygon_data = @polygon_styles.sub(/X1/, fromLeft1.to_s)
317
+ polygon_data = polygon_data.sub(/Y1/, fromTop.to_s)
318
+ polygon_data = polygon_data.sub(/X2/, fromLeft2.to_s)
319
+ polygon_data = polygon_data.sub(/Y2/, fromTop.to_s)
320
+ polygon_data = polygon_data.sub(/X3/, toLeft.to_s)
321
+ @tree_data += polygon_data.sub(/Y3/, toBot.to_s)
263
322
  end
264
323
 
265
324
  # If a node element text is wider than the sum of it's
@@ -271,9 +330,9 @@ EOD
271
330
  children = @e_list.get_children(id)
272
331
  @e_list.set_element_width(id, target)
273
332
 
274
- if(children.length > 0 )
333
+ if(children.length > 0 )
275
334
  delta = target - current
276
- target_delta = delta / children.length
335
+ target_delta = delta / children.length
277
336
 
278
337
  children.each do |child|
279
338
  child_width = @e_list.get_element_width(child)
@@ -282,27 +341,23 @@ EOD
282
341
  end
283
342
  end
284
343
 
285
- def img_get_txt_width(text, font, font_size, multiline = false)
344
+ def img_get_txt_width(text, font, font_size, multiline = true)
286
345
  parts = text.split("_", 2)
287
346
  main_before = parts[0].strip
288
347
  sub = parts[1]
289
348
  main = get_txt_only(main_before)
290
- if(main.contains_cjk?)
291
- main = 'n' * main.strip.size * 2
292
- else
293
- main
294
- end
295
349
  main_metrics = img_get_txt_metrics(main, font, font_size, multiline)
296
350
  width = main_metrics.width
297
351
  if sub
298
- if(sub.contains_cjk?)
299
- sub = 'n' * sub.strip.size * 2
300
- else
301
- sub
302
- end
303
- sub_metrics = img_get_txt_metrics(sub, font, font_size * SUBSCRIPT_CONST, multiline)
352
+ sub_metrics = img_get_txt_metrics(sub.strip, font, font_size * SUBSCRIPT_CONST, multiline)
304
353
  width += sub_metrics.width
305
354
  end
306
355
  return width
307
356
  end
357
+
358
+ def img_get_txt_height(text, font, font_size)
359
+ main_metrics = img_get_txt_metrics(text, font, font_size, false)
360
+ main_metrics.height
361
+ end
362
+
308
363
  end
@@ -21,24 +21,23 @@ class TreeGraph < Graph
21
21
 
22
22
  def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte,
23
23
  fontstyle, font, font_it, font_bd, font_itbd, font_math, font_cjk, font_size,
24
- margin)
24
+ margin, transparent)
25
25
 
26
26
  # Store class-specific parameters
27
- @fontstyle = fontstyle
28
- @font = multibyte ? font_cjk : font
29
- @font_size = font_size
30
- @font_it = font_it
31
- @font_bd = font_bd
32
- @font_itbd = font_itbd
33
- @font_math = font_math
34
- @font_cjk = font_cjk
35
- @margin = margin
27
+ @fontstyle = fontstyle
28
+ @font = multibyte ? font_cjk : font
29
+ @font_size = font_size
30
+ @font_it = font_it
31
+ @font_bd = font_bd
32
+ @font_itbd = font_itbd
33
+ @font_math = font_math
34
+ @font_cjk = font_cjk
35
+ @margin = margin
36
+ @transparent = transparent
36
37
 
37
38
  super(e_list, metrics, symmetrize, color, leafstyle, multibyte, @font, @font_size)
38
39
 
39
40
  # Initialize the image and colors
40
- @im = Image.new(@width, @height)
41
- @im.interlace = PlaneInterlace
42
41
  @gc = Draw.new
43
42
  @gc.font = @font
44
43
  @gc.pointsize(@font_size)
@@ -50,6 +49,12 @@ class TreeGraph < Graph
50
49
 
51
50
  def draw
52
51
  parse_list
52
+ @im = Image.new(@width, @height)
53
+ if @transparent
54
+ @im.matte_reset!
55
+ end
56
+ # @im.interlace = PlaneInterlace
57
+ @im.interlace = LineInterlace
53
58
  @gc.draw(@im)
54
59
  end
55
60
 
@@ -62,7 +67,12 @@ class TreeGraph < Graph
62
67
  # by Geoffrey Grosenbach
63
68
  def to_blob(fileformat='PNG')
64
69
  draw
65
- @im.border!(@margin, @margin, "white")
70
+ @im.trim!
71
+ if @transparent
72
+ @im.border!(@margin, @margin, "transparent")
73
+ else
74
+ @im.border!(@margin, @margin, "white")
75
+ end
66
76
  @im.format = fileformat
67
77
  @im.interlace = PlaneInterlace
68
78
  return @im.to_blob
@@ -80,7 +90,6 @@ class TreeGraph < Graph
80
90
  top = row2px(y)
81
91
  end
82
92
  left = x + @m[:b_side]
83
- bottom = top + @e_height
84
93
  right = left + w
85
94
 
86
95
  # Split the string into the main part and the
@@ -134,7 +143,14 @@ class TreeGraph < Graph
134
143
  # Calculate text size for the main and the
135
144
  # subscript part of the element
136
145
 
137
- main_width = img_get_txt_width(main, main_font, @font_size)
146
+
147
+ main_width = 0
148
+ main_height = 0
149
+ main.split(/\\n/).each do |l|
150
+ l_width = img_get_txt_width(l, main_font, @font_size)
151
+ main_width = l_width if main_width < l_width
152
+ main_height += img_get_txt_height(l, @font, @font_size)
153
+ end
138
154
 
139
155
  if /\A\=(.+)\=\z/ =~ sub
140
156
  sub = $1
@@ -174,14 +190,14 @@ class TreeGraph < Graph
174
190
 
175
191
  if sub != ""
176
192
  sub_width = img_get_txt_width(sub.to_s, sub_font, @sub_size)
193
+ sub_height = img_get_txt_height(sub.to_s, sub_font, @sub_size)
177
194
  else
178
195
  sub_width = 0
196
+ sub_height = 0
179
197
  end
180
198
 
181
199
  # Center text in the element
182
- txt_width = main_width + sub_width
183
-
184
- txt_pos = left + (right - left) / 2 - txt_width / 2
200
+ txt_pos = left + (right - left) / 2
185
201
 
186
202
  # Select apropriate color
187
203
  if(type == ETYPE_LEAF)
@@ -199,22 +215,33 @@ class TreeGraph < Graph
199
215
 
200
216
  # Draw main text
201
217
  @gc.pointsize(@font_size)
202
- main_x = txt_pos
218
+ @gc.kerning = 0
219
+ @gc.interline_spacing = 0
220
+ @gc.interword_spacing = 0
221
+
222
+ main_x = txt_pos - sub_width / 2
203
223
  main_y = top + @e_height - @m[:e_padd]
204
224
 
205
- @gc.interline_spacing = -(@main_height / 3)
225
+ # @gc.interline_spacing = -(@main_height / 3)
206
226
  @gc.font(main_font)
207
227
  @gc.decorate(main_decoration)
208
- @gc.text(main_x.ceil, main_y.ceil, main)
228
+ numlines = main.count("\\n")
229
+ if numlines > 1
230
+ @height = @height + @main_height * numlines
231
+ end
232
+ @gc.text_align(CenterAlign)
233
+ @gc.text(main_x.ceil, main_y.ceil, main.gsub("\\n", "\n"))
209
234
 
210
235
  # Draw subscript text
211
- if (sub.length > 0 )
236
+ if (sub != "" )
212
237
  @gc.pointsize(@sub_size)
213
- sub_x = txt_pos + main_width + @sub_space_width
214
- sub_y = top + (@e_height - @m[:e_padd] + @sub_size / 2)
238
+ sub_x = main_x + (main_width / 2) + (sub_width / 2)
239
+ sub_y = top + main_height + sub_height / 4
240
+ @height += sub_height / 4
215
241
  @gc.font(sub_font)
216
242
  @gc.decorate(sub_decoration)
217
- @gc.text(sub_x.ceil, sub_y.ceil, sub)
243
+ @gc.text_align(CenterAlign)
244
+ @gc.text(sub_x.ceil, sub_y.ceil, " " + sub.gsub("\\n", "\n"))
218
245
  end
219
246
  end
220
247
 
@@ -249,6 +276,7 @@ class TreeGraph < Graph
249
276
  fromLeft1 = (fromCenter + textW / 2).ceil
250
277
  fromLeft2 = (fromCenter - textW / 2).ceil
251
278
  toBot = (row2px(fromY - 1) + @e_height)
279
+
252
280
  if symmetrize
253
281
  toLeft = (toX + textW / 2 + @m[:b_side])
254
282
  else
@@ -283,7 +311,7 @@ class TreeGraph < Graph
283
311
  end
284
312
  end
285
313
 
286
- def img_get_txt_width(text, font, font_size, multiline = false)
314
+ def img_get_txt_width(text, font, font_size, multiline = true)
287
315
  parts = text.split("_", 2)
288
316
  main_before = parts[0].strip
289
317
  sub = parts[1]
@@ -1,4 +1,4 @@
1
1
  module RSyntaxTree
2
- VERSION = "0.8.5"
2
+ VERSION = "0.9.2"
3
3
  end
4
4
 
data/lib/rsyntaxtree.rb CHANGED
@@ -40,7 +40,8 @@ class RSGenerator
40
40
  key = keystr.to_sym
41
41
  case key
42
42
  when :data
43
- data = CGI.unescape(value)
43
+ data = value
44
+ # data = CGI.unescape(value)
44
45
  data = data.gsub('-AMP-', '&')
45
46
  .gsub('-PERCENT-', "%")
46
47
  .gsub('-PRIME-', "'")
@@ -49,7 +50,7 @@ class RSGenerator
49
50
  .gsub('-CABRACKET-', '>')
50
51
  new_params[key] = data
51
52
  new_params[:multibyte] = data.contains_cjk?
52
- when :symmetrize, :color, :autosub
53
+ when :symmetrize, :color, :autosub, :transparent
53
54
  new_params[key] = value && value != "off" ? true : false
54
55
  when :fontsize
55
56
  new_params[key] = value.to_i * FONT_SCALING
@@ -64,7 +65,7 @@ class RSGenerator
64
65
  new_params[:font_bd] = FONT_DIR + "/NotoSans-Bold.ttf"
65
66
  new_params[:font_bdit] = FONT_DIR + "/NotoSans-BoldItalic.ttf"
66
67
  new_params[:font_math] = FONT_DIR + "/NotoSansMath-Regular.ttf"
67
- new_params[:font_cjk] = FONT_DIR + "/NotoSansCJKjp-Regular.otf"
68
+ new_params[:font_cjk] = FONT_DIR + "/NotoSansJP-Regular.otf"
68
69
  new_params[:fontstyle] = "sans"
69
70
  elsif value == "noto-serif" || value == "serif"
70
71
  new_params[:font] = FONT_DIR + "/NotoSerif-Regular.ttf"
@@ -72,7 +73,7 @@ class RSGenerator
72
73
  new_params[:font_bd] = FONT_DIR + "/NotoSerif-Bold.ttf"
73
74
  new_params[:font_bdit] = FONT_DIR + "/NotoSerif-BoldItalic.ttf"
74
75
  new_params[:font_math] = FONT_DIR + "/NotoSansMath-Regular.ttf"
75
- new_params[:font_cjk] = FONT_DIR + "/NotoSerifCJKjp-Regular.otf"
76
+ new_params[:font_cjk] = FONT_DIR + "/NotoSerifJP-Regular.otf"
76
77
  new_params[:fontstyle] = "serif"
77
78
  elsif value == "cjk zenhei" || value == "cjk"
78
79
  new_params[:font] = FONT_DIR + "/wqy-zenhei.ttf"
@@ -88,7 +89,7 @@ class RSGenerator
88
89
  new_params[:font_bd] = FONT_DIR + "/lmroman10-bold.otf"
89
90
  new_params[:font_bdit] = FONT_DIR + "/lmroman10-bolditalic.otf"
90
91
  new_params[:font_math] = FONT_DIR + "/latinmodern-math.otf"
91
- new_params[:font_cjk] = FONT_DIR + "/NotoSerifCJKjp-Regular.otf"
92
+ new_params[:font_cjk] = FONT_DIR + "/NotoSerifJP-Regular.otf"
92
93
  new_params[:fontstyle] = "math"
93
94
  end
94
95
  else
@@ -98,30 +99,37 @@ class RSGenerator
98
99
 
99
100
  # defaults to the following
100
101
  @params = {
101
- :symmetrize => true,
102
- :color => true,
103
- :autosub => false,
104
- :fontsize => 18,
105
- :format => "png",
106
- :leafstyle => "auto",
107
- :filename => "syntree",
108
- :data => "",
109
- :margin => 0,
110
- :vheight => 1.0,
111
- :fontstyle => "sans",
112
- :font => "/NotoSansCJKjp-Regular.otf",
113
- :font_it => "/NotoSans-Italic.ttf",
114
- :font_bd => "/NotoSans-Bold.ttf",
115
- :font_bdit => "/NotoSans-BoldItalic.ttf",
116
- :font_math => "/NotoSansMath-Regular.ttf"
102
+ :symmetrize => true,
103
+ :color => true,
104
+ :autosub => false,
105
+ :transparent => false,
106
+ :fontsize => 18,
107
+ :format => "png",
108
+ :leafstyle => "auto",
109
+ :filename => "syntree",
110
+ :data => "",
111
+ :margin => 0,
112
+ :vheight => 1.0,
113
+ :fontstyle => "sans",
114
+ :font => "/NotoSansJP-Regular.otf",
115
+ :font_it => "/NotoSans-Italic.ttf",
116
+ :font_bd => "/NotoSans-Bold.ttf",
117
+ :font_bdit => "/NotoSans-BoldItalic.ttf",
118
+ :font_math => "/NotoSansMath-Regular.ttf"
117
119
  }
118
120
  @metrics = {
119
- :e_width => 120,
120
- :e_padd => 14,
121
- :v_space => 20,
122
- :h_space => 20,
123
- :b_side => 10,
124
- :b_topbot => 10
121
+ :e_width => 0,
122
+ :e_padd => 20,
123
+ :v_space => 0,
124
+ :h_space => 0,
125
+ :b_side => 0,
126
+ :b_topbot => 0
127
+ # :e_width => 120,
128
+ # :e_padd => 14,
129
+ # :v_space => 20,
130
+ # :h_space => 20,
131
+ # :b_side => 10,
132
+ # :b_topbot => 10
125
133
  }
126
134
 
127
135
  @params.merge! new_params
@@ -163,7 +171,7 @@ class RSGenerator
163
171
  elist = sp.get_elementlist
164
172
  graph = SVGGraph.new(elist, @metrics,
165
173
  @params[:symmetrize], @params[:color], @params[:leafstyle], @params[:multibyte],
166
- @params[:fontstyle], @params[:font], @params[:font_cjk], @params[:fontsize],
174
+ @params[:fontstyle], @params[:font], @params[:font_cjk], @params[:fontsize], @params[:margin], @params[:transparent]
167
175
  )
168
176
  graph.svg_data
169
177
  end
@@ -176,7 +184,7 @@ class RSGenerator
176
184
  graph = TreeGraph.new(elist, @metrics,
177
185
  @params[:symmetrize], @params[:color], @params[:leafstyle], @params[:multibyte],
178
186
  @params[:fontstyle], @params[:font], @params[:font_it], @params[:font_bd], @params[:font_bdit], @params[:font_math],
179
- @params[:font_cjk], @params[:fontsize], @params[:margin],
187
+ @params[:font_cjk], @params[:fontsize], @params[:margin], @params[:transparent]
180
188
  )
181
189
  graph.to_blob(@params[:format])
182
190
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsyntaxtree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoichiro Hasebe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-02 00:00:00.000000000 Z
11
+ date: 2021-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rmagick
@@ -67,13 +67,15 @@ files:
67
67
  - fonts/NotoSans-BoldItalic.ttf
68
68
  - fonts/NotoSans-Italic.ttf
69
69
  - fonts/NotoSans-Regular.ttf
70
- - fonts/NotoSansCJKjp-Regular.otf
70
+ - fonts/NotoSansJP-Bold.otf
71
+ - fonts/NotoSansJP-Regular.otf
71
72
  - fonts/NotoSansMath-Regular.ttf
72
73
  - fonts/NotoSerif-Bold.ttf
73
74
  - fonts/NotoSerif-BoldItalic.ttf
74
75
  - fonts/NotoSerif-Italic.ttf
75
76
  - fonts/NotoSerif-Regular.ttf
76
- - fonts/NotoSerifCJKjp-Regular.otf
77
+ - fonts/NotoSerifJP-Bold.otf
78
+ - fonts/NotoSerifJP-Regular.otf
77
79
  - fonts/latinmodern-math.otf
78
80
  - fonts/lmroman10-bold.otf
79
81
  - fonts/lmroman10-bolditalic.otf
Binary file
Binary file