svg_drawer 1.0.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 +7 -0
- data/LICENSE.txt +21 -0
- data/lib/fonts.yml +43 -0
- data/lib/svg_drawer/base.rb +215 -0
- data/lib/svg_drawer/circle.rb +139 -0
- data/lib/svg_drawer/line.rb +10 -0
- data/lib/svg_drawer/multipolyline.rb +144 -0
- data/lib/svg_drawer/path.rb +43 -0
- data/lib/svg_drawer/polyline.rb +171 -0
- data/lib/svg_drawer/table/blank_row.rb +32 -0
- data/lib/svg_drawer/table/border.rb +62 -0
- data/lib/svg_drawer/table/cell.rb +65 -0
- data/lib/svg_drawer/table/row.rb +127 -0
- data/lib/svg_drawer/table/table.rb +147 -0
- data/lib/svg_drawer/text_box.rb +153 -0
- data/lib/svg_drawer/utils/parameter_merger.rb +37 -0
- data/lib/svg_drawer/utils/rasem_wrapper.rb +14 -0
- data/lib/svg_drawer/utils/text.rb +48 -0
- data/lib/svg_drawer/version.rb +3 -0
- data/lib/svg_drawer.rb +31 -0
- data/svg_drawer.gemspec +21 -0
- metadata +106 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
module SvgDrawer
|
2
|
+
class Polyline < Base
|
3
|
+
# NOTE: reposition and scale behaviors can be moved to Base
|
4
|
+
# but that is not needed at the moment
|
5
|
+
#
|
6
|
+
# :expand ensures that if the elem is smaller than the given dimensions,
|
7
|
+
# it will be scaled *up* until its either X or Y dim hits the bounds
|
8
|
+
# :shrink is similar, but scales the element *down* until both X and Y
|
9
|
+
# dim fit within the bounds
|
10
|
+
#
|
11
|
+
# If either :expand or :shrink are given, :overflow is ignored
|
12
|
+
#
|
13
|
+
# :scale_size is taken into account only if :shrink and/or :expand are
|
14
|
+
# given, and determines whether the given size (i.e. stroke-width) is
|
15
|
+
# also scaled accordingly
|
16
|
+
#
|
17
|
+
# :dotspace, if given, will cause the line to become dotted
|
18
|
+
#
|
19
|
+
defaults fill: 'none',
|
20
|
+
stroke: 'black',
|
21
|
+
linecap: 'butt',
|
22
|
+
linejoin: 'miter',
|
23
|
+
size: 1,
|
24
|
+
x_reposition: 'none', # none/left/center/right
|
25
|
+
y_reposition: 'none', # none/top/middle/bottom
|
26
|
+
expand: false,
|
27
|
+
shrink: false,
|
28
|
+
dotspace: 0,
|
29
|
+
overflow: false,
|
30
|
+
scale: 1,
|
31
|
+
scale_size: true
|
32
|
+
|
33
|
+
def initialize(points, params = {})
|
34
|
+
@points = points
|
35
|
+
super(params)
|
36
|
+
end
|
37
|
+
|
38
|
+
def width
|
39
|
+
param(:overflow) ?
|
40
|
+
param(:width, calc_width) :
|
41
|
+
[param(:width, 0), calc_width].max
|
42
|
+
end
|
43
|
+
|
44
|
+
def height
|
45
|
+
param(:overflow) ?
|
46
|
+
param(:height, calc_height) :
|
47
|
+
[param(:height, 0), calc_height].max
|
48
|
+
end
|
49
|
+
|
50
|
+
def incomplete
|
51
|
+
@points.size < 4 || @points.size.odd? ? self : nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def min_x
|
55
|
+
@min_x ||= @points.each_slice(2).min_by(&:first).first - cap_size
|
56
|
+
end
|
57
|
+
|
58
|
+
def max_x
|
59
|
+
@max_x ||= @points.each_slice(2).max_by(&:first).first + cap_size
|
60
|
+
end
|
61
|
+
|
62
|
+
def min_y
|
63
|
+
@min_y ||= @points.each_slice(2).min_by(&:last).last - cap_size
|
64
|
+
end
|
65
|
+
|
66
|
+
def max_y
|
67
|
+
@max_y ||= @points.each_slice(2).max_by(&:last).last + cap_size
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def _draw(parent)
|
73
|
+
size = param(:scale_size) ? param(:size) : param(:size) / scale
|
74
|
+
dotspace = param(:scale_size) ? param(:dotspace) : param(:dotspace) / scale
|
75
|
+
dotsize = size
|
76
|
+
style = {}
|
77
|
+
|
78
|
+
if param(:linecap).eql?('round')
|
79
|
+
dotsize = 0
|
80
|
+
dotspace *= 2
|
81
|
+
end
|
82
|
+
|
83
|
+
# need symbol keys due to a bug in Rasem::SVGTag#write_styles
|
84
|
+
style[:fill] = param(:fill)
|
85
|
+
style[:stroke] = param(:stroke)
|
86
|
+
style[:'stroke-width'] = size
|
87
|
+
style[:'stroke-linecap'] = param(:linecap)
|
88
|
+
style[:'stroke-linejoin'] = param(:linejoin)
|
89
|
+
style[:'stroke-dasharray'] = "#{dotsize}, #{dotspace}" if dotspace > 0
|
90
|
+
|
91
|
+
Utils::RasemWrapper.group(parent, class: 'polyline') do |polyline_group|
|
92
|
+
poly = polyline_group.polyline(@points, style: style.dup)
|
93
|
+
poly.translate(translate_x, translate_y).scale(scale, scale)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def calc_width
|
98
|
+
calc_width_unscaled * scale
|
99
|
+
end
|
100
|
+
|
101
|
+
def calc_height
|
102
|
+
calc_height_unscaled * scale
|
103
|
+
end
|
104
|
+
|
105
|
+
def calc_width_unscaled
|
106
|
+
max_x - min_x
|
107
|
+
end
|
108
|
+
|
109
|
+
def calc_height_unscaled
|
110
|
+
max_y - min_y
|
111
|
+
end
|
112
|
+
|
113
|
+
def width_unscaled
|
114
|
+
param(:overflow) ?
|
115
|
+
param(:width, calc_width_unscaled) :
|
116
|
+
[param(:width, 0), calc_width_unscaled].max
|
117
|
+
end
|
118
|
+
|
119
|
+
def height_unscaled
|
120
|
+
param(:overflow) ?
|
121
|
+
param(:height, calc_height_unscaled) :
|
122
|
+
[param(:height, 0), calc_height_unscaled].max
|
123
|
+
end
|
124
|
+
|
125
|
+
def scale
|
126
|
+
[scale_x, scale_y].min * param(:scale)
|
127
|
+
end
|
128
|
+
|
129
|
+
def scale_x
|
130
|
+
return 1 unless param(:width) && (param(:expand) || param(:shrink))
|
131
|
+
scale = param(:width).to_d / calc_width_unscaled
|
132
|
+
return 1 if (scale > 1 && !param(:expand)) || (scale < 1 && !param(:shrink))
|
133
|
+
scale
|
134
|
+
end
|
135
|
+
|
136
|
+
def scale_y
|
137
|
+
return 1 unless param(:height) && (param(:expand) || param(:shrink))
|
138
|
+
scale = param(:height).to_d / calc_height_unscaled
|
139
|
+
return 1 if (scale > 1 && !param(:expand)) || (scale < 1 && !param(:shrink))
|
140
|
+
scale
|
141
|
+
end
|
142
|
+
|
143
|
+
def translate_x
|
144
|
+
width_diff = (width - calc_width)
|
145
|
+
|
146
|
+
case param(:x_reposition)
|
147
|
+
when 'left' then -min_x * scale
|
148
|
+
when 'center' then -min_x * scale + width_diff / 2
|
149
|
+
when 'right' then -min_x * scale + width_diff
|
150
|
+
when 'none' then 0
|
151
|
+
else raise "Bad x_reposition: #{param(:x_reposition)}. Valid are: [left, right, center, none]"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def translate_y
|
156
|
+
height_diff = height - calc_height
|
157
|
+
|
158
|
+
case param(:y_reposition)
|
159
|
+
when 'top' then -min_y * scale
|
160
|
+
when 'middle' then -min_y * scale + height_diff / 2
|
161
|
+
when 'bottom' then -min_y * scale + height_diff
|
162
|
+
when 'none' then 0
|
163
|
+
else raise "Bad y_reposition: #{param(:y_reposition)}. Valid are: [top, bottom, middle, none]"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def cap_size
|
168
|
+
param(:size).to_d / 2
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SvgDrawer
|
2
|
+
class BlankRow < Base
|
3
|
+
requires :columns
|
4
|
+
requires :width
|
5
|
+
requires :height
|
6
|
+
|
7
|
+
def incomplete
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def width
|
12
|
+
@width ||= param(:width)
|
13
|
+
end
|
14
|
+
|
15
|
+
def height
|
16
|
+
@height ||= param(:height)
|
17
|
+
end
|
18
|
+
|
19
|
+
def cell_widths
|
20
|
+
Array.new(param(:columns), 0)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def _draw(parent, _col_widths)
|
26
|
+
Utils::RasemWrapper.group(parent, class: param(:class), id: param(:id)) do |row_group|
|
27
|
+
draw_border(row_group)
|
28
|
+
row_group.rectangle(0, 0, width, height, fill: 'none', stroke: 'none')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module SvgDrawer
|
2
|
+
module Border
|
3
|
+
module_function
|
4
|
+
|
5
|
+
DEFAULT_STYLE = { stroke: 'black', size: 1 }.freeze
|
6
|
+
|
7
|
+
#
|
8
|
+
# Draw a rectangle with the given width and height
|
9
|
+
# The rectangle is actually 4 lines, with opacity of 1 or 0,
|
10
|
+
# depending on the values in the `borders` array.
|
11
|
+
# (e.g. [:left, :top])
|
12
|
+
#
|
13
|
+
# All lines share the same style, given by the border_style hash
|
14
|
+
# (see DEFAULT_STYLE for possible keys and their default values)
|
15
|
+
#
|
16
|
+
# For debugging purposes, lines can always be drawn even when there
|
17
|
+
# are no borders specified -- they are drawn transparent in this case.
|
18
|
+
# Drawing opacity=0 lines helps debugging in web inspector, but has
|
19
|
+
# some performance impact.
|
20
|
+
#
|
21
|
+
# @param parent [Rasem::SVGTagWithParent]
|
22
|
+
# @param width [Integer]
|
23
|
+
# @param height [Integer]
|
24
|
+
# @param borders [Array] (optional)
|
25
|
+
# @param border_style [Hash] (optional)
|
26
|
+
# @param svg_class [String] (optional)
|
27
|
+
# @param debug [Boolean] (optional) draw invisible borders
|
28
|
+
# @return [Rasem::SVGTagWithParent]
|
29
|
+
#
|
30
|
+
def draw(parent, width, height, borders, border_style, svg_class, debug)
|
31
|
+
return if !debug && (borders.nil? || borders.empty?)
|
32
|
+
|
33
|
+
style = DEFAULT_STYLE.merge(border_style || {})
|
34
|
+
style['stroke-width'] = style.delete(:size)
|
35
|
+
borders ||= []
|
36
|
+
|
37
|
+
line_points = {
|
38
|
+
top: [0, 0, width, 0],
|
39
|
+
right: [width, 0, width, height],
|
40
|
+
bottom: [width, height, 0, height],
|
41
|
+
left: [0, height, 0, 0]
|
42
|
+
}
|
43
|
+
|
44
|
+
klass = 'border'
|
45
|
+
klass.prepend("#{svg_class} ") if svg_class
|
46
|
+
|
47
|
+
Utils::RasemWrapper.group(parent, class: klass) do |group|
|
48
|
+
line_points.each do |border, points|
|
49
|
+
line_style = style.dup
|
50
|
+
|
51
|
+
# It is useful to draw an invisible border as this
|
52
|
+
# significantly helps debugging
|
53
|
+
unless borders.include?(border)
|
54
|
+
debug ? line_style[:opacity] = 0 : next
|
55
|
+
end
|
56
|
+
|
57
|
+
group.line(*points, line_style)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module SvgDrawer
|
2
|
+
class Cell < Base
|
3
|
+
def width
|
4
|
+
return @width if @width
|
5
|
+
ensure_complete!
|
6
|
+
@width = [param(:width, 0), @content.width].max
|
7
|
+
end
|
8
|
+
|
9
|
+
def height
|
10
|
+
return @height if @height
|
11
|
+
ensure_complete!
|
12
|
+
@height = [param(:height, 0), @content.height].max
|
13
|
+
end
|
14
|
+
|
15
|
+
def incomplete
|
16
|
+
@content.nil? ? self : @content.incomplete
|
17
|
+
end
|
18
|
+
|
19
|
+
def content(element = nil)
|
20
|
+
return @content unless element
|
21
|
+
raise TypeError, 'Argument must to respond to #draw' unless element.respond_to?(:draw)
|
22
|
+
element.update_params!(inherited: child_params)
|
23
|
+
@content = element
|
24
|
+
end
|
25
|
+
|
26
|
+
def text_box(text, params = {})
|
27
|
+
@content = TextBox.new(text, params.merge(inherited: child_params))
|
28
|
+
end
|
29
|
+
|
30
|
+
def path(path_components, params = {})
|
31
|
+
@content = Path.new(path_components, params.merge(inherited: child_params))
|
32
|
+
end
|
33
|
+
|
34
|
+
def polyline(points, params = {})
|
35
|
+
@content = Polyline.new(points, params.merge(inherited: child_params))
|
36
|
+
end
|
37
|
+
|
38
|
+
def multipolyline(strokes, params = {})
|
39
|
+
@content = Multipolyline.new(strokes, params.merge(inherited: child_params))
|
40
|
+
end
|
41
|
+
|
42
|
+
def line(points, params = {})
|
43
|
+
@content = Line.new(points, params.merge(inherited: child_params))
|
44
|
+
end
|
45
|
+
|
46
|
+
def circle(center, radius, params = {})
|
47
|
+
@content = Circle.new(center, radius, params.merge(inherited: child_params))
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# See Row#draw for info on col_width and row_height
|
52
|
+
#
|
53
|
+
# @param parent [Rasem::SVGTagWithParent]
|
54
|
+
# @param col_width [Integer] Table-wide max colum width
|
55
|
+
# @param row_height [Integer] Table-wide max row height
|
56
|
+
# @return [Rasem::SVGTagWithParent]
|
57
|
+
#
|
58
|
+
def _draw(parent)
|
59
|
+
Utils::RasemWrapper.group(parent, class: param(:class), id: param(:id)) do |cell_group|
|
60
|
+
draw_border(cell_group)
|
61
|
+
@content.draw(cell_group, debug: @debug)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module SvgDrawer
|
2
|
+
class Row < Base
|
3
|
+
requires :columns
|
4
|
+
|
5
|
+
special :width # row width is not the same as cell width
|
6
|
+
special :columns # makes no sense for a cell
|
7
|
+
special :col_widths # makes no sense for a cell
|
8
|
+
|
9
|
+
def width
|
10
|
+
ensure_complete!
|
11
|
+
sum_width = cell_widths.reduce(&:+)
|
12
|
+
[param(:width, 0), sum_width].max
|
13
|
+
end
|
14
|
+
|
15
|
+
def height
|
16
|
+
ensure_complete!
|
17
|
+
[param(:height, 0), cell_heights.max].max
|
18
|
+
end
|
19
|
+
|
20
|
+
def incomplete
|
21
|
+
cells.size != param(:columns) ? self : find_incomplete_descendant
|
22
|
+
end
|
23
|
+
|
24
|
+
def cell_widths
|
25
|
+
ensure_complete!
|
26
|
+
cells.map(&:width)
|
27
|
+
end
|
28
|
+
|
29
|
+
def cell_heights
|
30
|
+
ensure_complete!
|
31
|
+
cells.map(&:height)
|
32
|
+
end
|
33
|
+
|
34
|
+
def col_widths
|
35
|
+
Table.col_widths(param(:col_widths), param(:width), param(:columns))
|
36
|
+
end
|
37
|
+
|
38
|
+
def cells
|
39
|
+
@cells ||= []
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_cell(cell)
|
43
|
+
raise TypeError, "Expected Cell, got: #{cell.class}" unless cell.is_a?(Cell)
|
44
|
+
cell.update_params!(inherited: cell_params)
|
45
|
+
cells << cell
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# @param params [Hash] cell params.
|
51
|
+
# @return [Row] self
|
52
|
+
#
|
53
|
+
def cell(params = {})
|
54
|
+
raise 'Cannot add more cells' unless incomplete
|
55
|
+
cell = Cell.new(params.merge(inherited: cell_params))
|
56
|
+
yield(cell)
|
57
|
+
cells << cell
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def text_cell(text, params = {})
|
62
|
+
cell(params) { |c| c.text_box(text) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def path_cell(path_components, params = {})
|
66
|
+
cell(params) { |c| c.path(path_components) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def line_cell(points, params = {})
|
70
|
+
cell(params) { |c| c.line(points) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def polyline_cell(points, params = {})
|
74
|
+
cell(params) { |c| c.polyline(points) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def multipolyline_cell(strokes, params = {})
|
78
|
+
cell(params) { |c| c.multipolyline(strokes) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def circle_cell(center, radius, params = {})
|
82
|
+
cell(params) { |c| c.circle(center, radius) }
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
#
|
88
|
+
# A note on cell widths:
|
89
|
+
# Cells are drawed not with their initial widths, but with the
|
90
|
+
# table-wide maximum width for the corresponding columns.
|
91
|
+
# This must happen at draw time, as we can't know what the max col
|
92
|
+
# width is until we have added all rows for the entire table.
|
93
|
+
#
|
94
|
+
# Similarly, for the heights:
|
95
|
+
# Cells are not drawed with their initial heigths, but with the
|
96
|
+
# row-wide maximum height.
|
97
|
+
# This must happen at draw time, as we can't know what the max cell
|
98
|
+
# height is until we have added all cells for this row.
|
99
|
+
#
|
100
|
+
# @param parent [Rasem::SVGTagWithParent]
|
101
|
+
# @param col_widths [Array] Table-wide max column widths
|
102
|
+
# @return [Rasem::SVGTagWithParent]
|
103
|
+
#
|
104
|
+
def _draw(parent, max_col_widths)
|
105
|
+
Utils::RasemWrapper.group(parent, class: param(:class), id: param(:id)) do |row_group|
|
106
|
+
draw_border(row_group, width_override: max_col_widths.reduce(&:+))
|
107
|
+
|
108
|
+
cells.zip(max_col_widths).reduce(0) do |x, (cell, col_width)|
|
109
|
+
cell.draw(row_group, debug: @debug).translate(x, 0)
|
110
|
+
x + col_width
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def cell_params
|
116
|
+
return child_params unless col_widths && col_widths[cells.size]
|
117
|
+
child_params.merge(width: col_widths[cells.size])
|
118
|
+
end
|
119
|
+
|
120
|
+
def find_incomplete_descendant
|
121
|
+
cells.each.with_object(nil) do |cell, _|
|
122
|
+
res = cell.incomplete
|
123
|
+
break res if res
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module SvgDrawer
|
2
|
+
class Table < Base
|
3
|
+
requires :columns
|
4
|
+
|
5
|
+
special :height # table height is not the same as row height
|
6
|
+
special :row_height # makes no sense for a row
|
7
|
+
|
8
|
+
defaults col_widths: nil
|
9
|
+
|
10
|
+
#
|
11
|
+
# Infer col_widths from width (if needed)
|
12
|
+
#
|
13
|
+
def self.col_widths(col_widths, width, columns)
|
14
|
+
return if col_widths.nil? && width.nil?
|
15
|
+
sum_width = col_widths.reduce(&:+) if col_widths
|
16
|
+
|
17
|
+
if col_widths && width && sum_width != width
|
18
|
+
raise ArgumentError, "Sum of given col widths (#{col_widths}) doesn't match total element width (#{width})"
|
19
|
+
end
|
20
|
+
|
21
|
+
col_widths || Array.new(columns, width.to_d / columns)
|
22
|
+
end
|
23
|
+
|
24
|
+
def width
|
25
|
+
ensure_complete!
|
26
|
+
sum_width = col_widths ? col_widths.reduce(&:+) : 0
|
27
|
+
max_width = max_col_widths.reduce(&:+)
|
28
|
+
|
29
|
+
[sum_width, max_width].max
|
30
|
+
end
|
31
|
+
|
32
|
+
def height
|
33
|
+
ensure_complete!
|
34
|
+
sum_height = rows.reduce(0) { |a, e| a + e.height }
|
35
|
+
[param(:height, 0), sum_height].max
|
36
|
+
end
|
37
|
+
|
38
|
+
def incomplete
|
39
|
+
rows.none? ? self : find_incomplete_descendant
|
40
|
+
end
|
41
|
+
|
42
|
+
def rows
|
43
|
+
@rows ||= []
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_row(row)
|
47
|
+
raise TypeError, "Expected Row, got: #{row.class}" unless row.is_a?(Row)
|
48
|
+
row.update_params!(inherited: row_params)
|
49
|
+
rows << row
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# The params hash can contain a special :height value
|
54
|
+
# It will be used instead of the @row_height when creating the row
|
55
|
+
#
|
56
|
+
# @param params [Hash] row params
|
57
|
+
# @return [Table] self
|
58
|
+
#
|
59
|
+
def row(params = {})
|
60
|
+
row = Row.new(params.merge(inherited: row_params))
|
61
|
+
yield(row)
|
62
|
+
rows << row
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def text_row(texts, params = {})
|
67
|
+
texts = texts.nil? ? [nil] : Array(texts)
|
68
|
+
row(params) { |r| texts.each { |text| r.text_cell(text) } }
|
69
|
+
end
|
70
|
+
|
71
|
+
def path_row(path_components, params = {})
|
72
|
+
row(params) { |r| r.path_cell(path_components) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def line_row(points, params = {})
|
76
|
+
row(params) { |r| r.line_cell(points) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def polyline_row(points, params = {})
|
80
|
+
row(params) { |r| r.polyline_cell(points) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def multipolyline_row(strokes, params = {})
|
84
|
+
row(params) { |r| r.multipolyline_cell(strokes) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def circle_row(center, radius, params = {})
|
88
|
+
row(params) { |r| r.circle_cell(center, radius) }
|
89
|
+
end
|
90
|
+
|
91
|
+
def sub_table_row(params = {})
|
92
|
+
t = Table.new(params)
|
93
|
+
row { |r| r.cell { |c| c.content(t) && yield(t) } }
|
94
|
+
end
|
95
|
+
|
96
|
+
def blank_row(params = {})
|
97
|
+
raise ArgumentError, ':height required' if !param(:row_height) && !params[:height]
|
98
|
+
rows << BlankRow.new(params.merge(inherited: row_params))
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def col_widths
|
103
|
+
Table.col_widths(param(:col_widths), param(:width), param(:columns))
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
#
|
109
|
+
# The dimension overrides given when the table is actually
|
110
|
+
# the child of a (parent) table cell.
|
111
|
+
# In this case the overrides are used to draw proper borders
|
112
|
+
# (since the Cell element of the parent determines its)
|
113
|
+
#
|
114
|
+
# @param parent [Rasem::SVGTagWithParent]
|
115
|
+
# @param width_override [Integer] (optional) container width
|
116
|
+
# @param height_override [Integer] (optional) container height
|
117
|
+
# @return [Rasem::SVGTagWithParent]
|
118
|
+
#
|
119
|
+
def _draw(parent)
|
120
|
+
Utils::RasemWrapper.group(parent, class: param(:class), id: param(:id)) do |table_group|
|
121
|
+
draw_border(table_group)
|
122
|
+
|
123
|
+
rows.reduce(0) do |y, row|
|
124
|
+
row.draw(table_group, max_col_widths, debug: @debug).translate(0, y)
|
125
|
+
y + row.height
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def row_params
|
131
|
+
param(:row_height)
|
132
|
+
return child_params unless param(:row_height)
|
133
|
+
child_params.merge(height: param(:row_height))
|
134
|
+
end
|
135
|
+
|
136
|
+
def find_incomplete_descendant
|
137
|
+
rows.each.with_object(nil) do |row, _|
|
138
|
+
res = row.incomplete
|
139
|
+
break res if res
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def max_col_widths
|
144
|
+
rows.map(&:cell_widths).transpose.map(&:max)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|