Skip to content

Commit d2671c5

Browse files
committed
fully working legend box and legends
1 parent d194c07 commit d2671c5

5 files changed

Lines changed: 125 additions & 81 deletions

File tree

lib/rubyplot/artist/legend.rb

Lines changed: 30 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,56 @@
11
module Rubyplot
22
module Artist
33
class Legend < Artist::Base
4+
TOP_MARGIN = 2.5
5+
BOTTOM_MARGIN = 2.5
6+
# Space between the color box and the legend text.
7+
BOX_AND_TEXT_SPACE = 5.0
48
attr_reader :legend_box_size, :font, :font_size, :font_color
5-
6-
# text - [String] String containing name of this legend.
7-
# colors - [String] String of corresponding color.
8-
def initialize(axes, text:, color:,abs_x:,abs_y:)
9-
super(axes.backend, abs_x, abs_y)
9+
10+
def initialize(legend_box, axes, text:, color:,abs_x:,abs_y:)
11+
super(legend_box.backend, abs_x, abs_y)
12+
@legend_box = legend_box
1013
@axes = axes
1114
@text = text
1215
@color = color
13-
@legend_box_size = 20.0 # size of the color box of the legend.
16+
@legend_box_size = @legend_box.per_legend_height -
17+
(TOP_MARGIN + BOTTOM_MARGIN) # size of the color box of the legend.
1418
@font_size = 20.0
1519
@font = @axes.font
1620
@font_color = @axes.font_color
1721
configure_legend_color_box
1822
configure_legend_text
19-
calculate_legend_size
20-
calculate_offsets
2123
end
2224

2325
def draw
24-
draw_legend_text
25-
draw_legend_color_indicator # FIXME: make a new Artist::Rectangle object.
26+
@legend_color_box.draw
27+
@text.draw
2628
end
2729

2830
private
2931

3032
def configure_legend_color_box
31-
33+
@legend_color_box = Rubyplot::Artist::Rectangle.new(
34+
self,
35+
abs_x: @abs_x,
36+
abs_y: @abs_y + TOP_MARGIN,
37+
width: @legend_box_size,
38+
height: @legend_box_size,
39+
border_color: @color,
40+
fill_color: @color
41+
)
3242
end
3343

3444
def configure_legend_text
35-
36-
end
37-
38-
def draw_legend_text
39-
scaled_width = @axes.geometry.raw_columns * @axes.scale
40-
scaled_width = scaled_width >=1 ? scaled_width : 1
41-
@axes.backend.draw_text(@text,
42-
font_color: @font_color,
43-
font: @font,
44-
pointsize: @font_size * @axes.scale,
45-
stroke: 'transparent',
46-
width: scaled_width,
47-
height: 1.0,
48-
x: @current_x_offset + (@legend_box_size * 1.7),
49-
y: @current_y_offset
50-
)
51-
end
52-
53-
def draw_legend_color_indicator
54-
@axes.backend.draw_rectangle(x1: @current_x_offset,
55-
y1: @current_y_offset - @legend_box_size/2.0,
56-
x2: @current_x_offset + @legend_box_size,
57-
y2: @current_y_offset + @legend_box_size/2.0,
58-
color: @color,
59-
stroke: 'transparent'
60-
)
61-
end
62-
63-
# FIXME: should work for multiple legeuidends.
64-
def calculate_offsets
65-
@current_x_offset = (@axes.geometry.raw_columns -
66-
@label_widths.first.inject(:+))/2
67-
@current_y_offset = if @axes.geometry.legend_at_bottom
68-
@axes.graph_height + @axes.title_margin
69-
else
70-
if @axes.geometry.hide_title
71-
@axes.geometry.top_margin + @axes.title_margin
72-
else
73-
@axes.geometry.top_margin +
74-
@axes.title_margin + @axes.title_caps_height
75-
end
76-
end
77-
end
78-
79-
def calculate_legend_size
80-
# FIXME: below array consists of two arrays. If the legend overflows into another line,
81-
# it removes the element from the first array and put it in the second array.
82-
# so basically first array is for legends which have not overflowed and the second
83-
# is one which have. possibly rethink this data structure.
84-
@label_widths = [[]] # for calculating line wrap
85-
width, _ = @axes.backend.get_text_width_height @text
86-
label_width = width + @legend_box_size * 2.7 # FIXME: make value a global constant
87-
@label_widths.last.push label_width
88-
89-
if @label_widths.last.inject(:+) > (@axes.geometry.raw_columns * 0.9)
90-
@label_widths.push [@label_widths.last.pop]
91-
end
45+
@text = Rubyplot::Artist::Text.new(
46+
@text,
47+
self,
48+
abs_x: @abs_x + @legend_box_size + BOX_AND_TEXT_SPACE,
49+
abs_y: @legend_color_box.abs_y + @legend_box_size - 2.5,
50+
font: @font,
51+
color: @font_color,
52+
pointsize: @font_size
53+
)
9254
end
9355
end # class Legend
9456
end # class Artist

lib/rubyplot/artist/legend_box.rb

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,84 @@
11
module Rubyplot
22
module Artist
33
class LegendBox < Base
4-
MAX_WIDTH = 50.0
5-
MAX_HEIGHT = 30.0
4+
# Ratio of total height of legend box that is the top margin.
5+
TOP_SPACING_RATIO = 0.1
6+
# Ratio of the total height of the legend box that is the bottom margin.
7+
BOTTOM_SPACING_RATIO = 0.1
8+
# Ratio of the total width of the legend box that is the left margin.
9+
LEFT_SPACING_RATIO = 0.1
10+
# Ratio of the total width of the legend box that is the right margin.
11+
RIGHT_SPACING_RATIO = 0.1
12+
13+
attr_accessor :border_color
614

715
def initialize(axes, abs_x:, abs_y:)
816
super(axes.backend, abs_x, abs_y)
917
@axes = axes
18+
@border_color = "#000000"
1019
@legends = []
20+
configure_dimensions
1121
configure_legends
22+
configure_legend_box
1223
end
1324

1425
def draw
15-
26+
@bounding_box.draw
27+
@legends.each(&:draw)
28+
end
29+
30+
def top_margin
31+
TOP_SPACING_RATIO * @legends_height
32+
end
33+
34+
def bottom_margin
35+
BOTTOM_SPACING_RATIO * @legends_height
36+
end
37+
38+
def left_margin
39+
LEFT_SPACING_RATIO * @legends_width
40+
end
41+
42+
def right_margin
43+
RIGHT_SPACING_RATIO * @legends_width
44+
end
45+
46+
# Calculation of the height that each legend takes.
47+
def per_legend_height
48+
25.0
1649
end
1750

1851
private
1952

53+
def configure_legend_box
54+
@bounding_box = Rubyplot::Artist::Rectangle.new(
55+
self,
56+
abs_x: @abs_x,
57+
abs_y: @abs_y,
58+
width: @width,
59+
height: @height,
60+
border_color: @border_color
61+
)
62+
end
63+
64+
def configure_dimensions
65+
@legends_height = @axes.plots.size * per_legend_height
66+
@legends_width = 0.2 * @axes.width
67+
@height = @legends_height + top_margin + bottom_margin
68+
@width = @legends_width + left_margin + right_margin
69+
end
70+
2071
def configure_legends
21-
72+
@axes.plots.each_with_index do |plot, count|
73+
@legends << Rubyplot::Artist::Legend.new(
74+
self,
75+
@axes,
76+
text: plot.label,
77+
color: plot.color,
78+
abs_x: @abs_x + left_margin,
79+
abs_y: @abs_y + count * per_legend_height + top_margin
80+
)
81+
end
2282
end
2383
end # class LegendBox
2484
end # module Artist

lib/rubyplot/artist/plot/base.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ def initialize axes
2020
@stroke_opacity = 1.0
2121
end
2222

23+
def label
24+
@data[:label]
25+
end
26+
27+
def color
28+
@data[:color]
29+
end
30+
2331
def label= label
2432
@data[:label] = label
2533
end

lib/rubyplot/artist/rectangle.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
module Rubyplot
22
module Artist
33
class Rectangle < Base
4-
attr_reader :width, :height, :color
4+
attr_reader :width, :height, :border_color, :fill_color
55

6-
def initialize(owner,abs_x:,abs_y:,width:,height:,color:)
6+
def initialize(owner,abs_x:,abs_y:,width:,height:,border_color:,fill_color: nil)
77
super(owner.backend, abs_x, abs_y)
88
@height = height
99
@width = width
10-
@color = color
10+
@border_color = border_color
11+
@fill_color = fill_color
1112
end
1213

1314
def draw
@@ -16,7 +17,8 @@ def draw
1617
y1: @abs_y,
1718
x2: @abs_x + @width,
1819
y2: @abs_y + @height,
19-
color: @color
20+
border_color: @border_color,
21+
fill_color: @fill_color
2022
)
2123
end
2224
end # class Rectangle

lib/rubyplot/backend/magick_wrapper.rb

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,30 @@ def draw_text(text,font_color:,font: nil,pointsize:,stroke:,
8282
@draw.rotation = 90.0 if rotation
8383
end
8484

85-
def draw_rectangle x1:,y1:,x2:,y2:,color: '#000000', stroke: 'transparent'
86-
@draw.stroke stroke
87-
@draw.fill color
88-
@draw.rectangle x1, y1, x2, y2
85+
# Draw a rectangle.
86+
def draw_rectangle(x1:,y1:,x2:,y2:,border_color: '#000000',stroke: 'transparent',
87+
fill_color: nil, stroke_width: 1.0)
88+
if fill_color # solid rectangle
89+
@draw.stroke stroke
90+
@draw.fill fill_color
91+
@draw.stroke_width stroke_width
92+
@draw.rectangle x1, y1, x2, y2
93+
else # just edges
94+
@draw.stroke_width stroke_width
95+
@draw.fill border_color
96+
@draw.line x1, y1, x1 + (x2-x1), y1 # top line
97+
@draw.line x1 + (x2-x1), y1, x2, y2 # right line
98+
@draw.line x2, y2, x1, y1 + (y2-y1) # bottom line
99+
@draw.line x1, y1, x1, y1 + (y2-y1) # left line
100+
end
89101
end
90102

91103
def draw_line(x1:,y1:,x2:,y2:,color: '#000000', stroke: 'transparent',
92104
stroke_opacity: 0.0, stroke_width: 2.0)
93105
@draw.stroke_opacity stroke_opacity
94106
@draw.stroke_width stroke_width
95107
@draw.fill color
96-
@draw = @draw.line x1, y1, x2, y2
108+
@draw.line x1, y1, x2, y2
97109
end
98110

99111
def draw_circle(x:,y:,radius:,stroke_opacity:,stroke_width:,color:)

0 commit comments

Comments
 (0)