1use crate::theme::{LegendPosition, Theme};
2
3use super::Rect;
4
5pub struct PlotLayout {
7 pub total: Rect,
8 pub plot_area: Rect,
9 pub title_area: Rect,
10 pub subtitle_area: Rect,
11 pub caption_area: Rect,
12 pub x_axis_area: Rect,
13 pub y_axis_area: Rect,
14 pub legend_area: Rect,
15}
16
17impl PlotLayout {
18 pub fn compute(
20 width: f64,
21 height: f64,
22 theme: &Theme,
23 has_title: bool,
24 has_legend: bool,
25 ) -> Self {
26 Self::compute_full(width, height, theme, has_title, false, false, has_legend)
27 }
28
29 pub fn compute_full(
31 width: f64,
32 height: f64,
33 theme: &Theme,
34 has_title: bool,
35 has_subtitle: bool,
36 has_caption: bool,
37 has_legend: bool,
38 ) -> Self {
39 let margin = &theme.plot_margin;
40
41 let title_height = if has_title {
42 theme.title.size * 2.0
43 } else {
44 0.0
45 };
46
47 let subtitle_height = if has_subtitle {
48 theme.subtitle.size * 1.5
49 } else {
50 0.0
51 };
52
53 let caption_height = if has_caption {
54 theme.caption.size * 1.8
55 } else {
56 0.0
57 };
58
59 let x_axis_height = theme.axis_ticks_length
60 + if theme.axis_text_x.visible {
61 if theme.axis_text_x.angle.abs() > 10.0 {
63 theme.axis_text_x.size * 5.0
64 } else {
65 theme.axis_text_x.size + 4.0
66 }
67 } else {
68 0.0
69 }
70 + if theme.axis_title_x.visible {
71 theme.axis_title_x.size + 8.0
72 } else {
73 0.0
74 };
75
76 let y_axis_width = theme.axis_ticks_length
77 + if theme.axis_text_y.visible {
78 theme.axis_text_y.size * 3.5 + 4.0
79 } else {
80 0.0
81 }
82 + if theme.axis_title_y.visible {
83 theme.axis_title_y.size + 8.0
84 } else {
85 0.0
86 };
87
88 let legend_size = if has_legend {
89 theme.legend_margin.left
90 + theme.legend_key_width
91 + theme.legend_spacing
92 + theme.legend_text.size * 6.0
93 + theme.legend_margin.right
94 } else {
95 0.0
96 };
97
98 let (legend_right, legend_left, legend_top, legend_bottom) = if has_legend {
100 match theme.legend_position {
101 LegendPosition::Right => (legend_size, 0.0, 0.0, 0.0),
102 LegendPosition::Left => (0.0, legend_size, 0.0, 0.0),
103 LegendPosition::Top => (0.0, 0.0, legend_size, 0.0),
104 LegendPosition::Bottom => (0.0, 0.0, 0.0, legend_size),
105 LegendPosition::None | LegendPosition::Inside(..) => (0.0, 0.0, 0.0, 0.0),
107 }
108 } else {
109 (0.0, 0.0, 0.0, 0.0)
110 };
111
112 let plot_x = margin.left + y_axis_width + legend_left;
113 let plot_y = margin.top + title_height + subtitle_height + legend_top;
114 let plot_width =
115 width - margin.left - margin.right - y_axis_width - legend_right - legend_left;
116 let plot_height = height
117 - margin.top
118 - margin.bottom
119 - title_height
120 - subtitle_height
121 - caption_height
122 - x_axis_height
123 - legend_top
124 - legend_bottom;
125
126 let plot_width = plot_width.max(50.0);
127 let plot_height = plot_height.max(50.0);
128
129 PlotLayout {
130 total: Rect {
131 x: 0.0,
132 y: 0.0,
133 width,
134 height,
135 },
136 plot_area: Rect {
137 x: plot_x,
138 y: plot_y,
139 width: plot_width,
140 height: plot_height,
141 },
142 title_area: Rect {
143 x: plot_x,
144 y: margin.top,
145 width: plot_width,
146 height: title_height,
147 },
148 subtitle_area: Rect {
149 x: plot_x,
150 y: margin.top + title_height,
151 width: plot_width,
152 height: subtitle_height,
153 },
154 caption_area: Rect {
155 x: plot_x,
156 y: plot_y + plot_height + x_axis_height,
157 width: plot_width,
158 height: caption_height,
159 },
160 x_axis_area: Rect {
161 x: plot_x,
162 y: plot_y + plot_height,
163 width: plot_width,
164 height: x_axis_height,
165 },
166 y_axis_area: Rect {
167 x: margin.left + legend_left,
168 y: plot_y,
169 width: y_axis_width,
170 height: plot_height,
171 },
172 legend_area: Rect {
173 x: plot_x + plot_width,
174 y: plot_y,
175 width: legend_size,
176 height: plot_height,
177 },
178 }
179 }
180}