ratatui_widgets/canvas/map.rs
1use ratatui_core::style::Color;
2use strum::{Display, EnumString};
3
4use crate::canvas::world::{WORLD_HIGH_RESOLUTION, WORLD_LOW_RESOLUTION};
5use crate::canvas::{Painter, Shape};
6
7/// Defines how many points are going to be used to draw a [`Map`].
8///
9/// You generally want a [high](MapResolution::High) resolution map.
10#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
11pub enum MapResolution {
12 /// A lesser resolution for the [`Map`] [`Shape`].
13 ///
14 /// Contains about 1000 points.
15 #[default]
16 Low,
17 /// A higher resolution for the [`Map`] [`Shape`].
18 ///
19 /// Contains about 5000 points, you likely want to use [`Marker::Braille`] with this.
20 ///
21 /// [`Marker::Braille`]: (ratatui_core::symbols::Marker::Braille)
22 High,
23}
24
25impl MapResolution {
26 const fn data(self) -> &'static [(f64, f64)] {
27 match self {
28 Self::Low => &WORLD_LOW_RESOLUTION,
29 Self::High => &WORLD_HIGH_RESOLUTION,
30 }
31 }
32}
33
34/// A world map
35///
36/// A world map can be rendered with different [resolutions](MapResolution) and [colors](Color).
37#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
38pub struct Map {
39 /// The resolution of the map.
40 ///
41 /// This is the number of points used to draw the map.
42 pub resolution: MapResolution,
43 /// Map color
44 ///
45 /// This is the color of the points of the map.
46 pub color: Color,
47}
48
49impl Shape for Map {
50 fn draw(&self, painter: &mut Painter) {
51 for (x, y) in self.resolution.data() {
52 if let Some((x, y)) = painter.get_point(*x, *y) {
53 painter.paint(x, y, self.color);
54 }
55 }
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use alloc::string::ToString;
62
63 use ratatui_core::buffer::Buffer;
64 use ratatui_core::layout::Rect;
65 use ratatui_core::symbols::Marker;
66 use ratatui_core::widgets::Widget;
67 use strum::ParseError;
68
69 use super::*;
70 use crate::canvas::Canvas;
71
72 #[test]
73 fn map_resolution_to_string() {
74 assert_eq!(MapResolution::Low.to_string(), "Low");
75 assert_eq!(MapResolution::High.to_string(), "High");
76 }
77
78 #[test]
79 fn map_resolution_from_str() {
80 assert_eq!("Low".parse(), Ok(MapResolution::Low));
81 assert_eq!("High".parse(), Ok(MapResolution::High));
82 assert_eq!(
83 "".parse::<MapResolution>(),
84 Err(ParseError::VariantNotFound)
85 );
86 }
87
88 #[test]
89 fn default() {
90 let map = Map::default();
91 assert_eq!(map.resolution, MapResolution::Low);
92 assert_eq!(map.color, Color::Reset);
93 }
94
95 #[test]
96 fn draw_low() {
97 let mut buffer = Buffer::empty(Rect::new(0, 0, 80, 40));
98 let canvas = Canvas::default()
99 .marker(Marker::Dot)
100 .x_bounds([-180.0, 180.0])
101 .y_bounds([-90.0, 90.0])
102 .paint(|context| {
103 context.draw(&Map::default());
104 });
105 canvas.render(buffer.area, &mut buffer);
106 let expected = Buffer::with_lines([
107 " ",
108 " • ",
109 " • •• •••••••• •• •••• ••••• ••• •• ••• ",
110 " ••••••••••••••• • •••• • • ••••••• ••• ",
111 " • •••• ••••••••••••••• •• •• • ••• •• •••• •• ••••••• ••• ",
112 "••••• •••••••••••• •••• • •••••• •••• • ••• ••••• •",
113 " •• • • •••• •••••••• •••• •• • •• • ••• •• •••",
114 " •••• ••• •••••• ••••• • •• •••••• • ••••• ",
115 "••••• ••• • •• •• ••••••• •• •• •• ",
116 " •• •••• ••••• •• • • • •• ",
117 " • • ••••••• •• •••• ••• •• • •• • •• ",
118 " • •• ••••••••• • •• •••• • ",
119 " •• •• • • • •• • ••••• ",
120 " •• ••• • •••• • • • ",
121 " • • •• • •• •• • • ",
122 " •• • ••••••• • • • • • •• • ",
123 " ••••••••• • •• • • • •• • •• ",
124 " •• •• • ••• • ••• •• ",
125 " ••• • • • • • •• ••• ••• ",
126 " • • •• • •• ",
127 " • • ••• • • ••• ••• ",
128 " • • • • • ••• ",
129 " • • • • • • • ",
130 " • • • • ••• •• •",
131 " • • • • •• • • • ",
132 " • • • • • ",
133 " • • • • • ",
134 " •• •• •• •• • • ",
135 " • • ••• •• ",
136 " • • •• •• ",
137 " • • ",
138 " ••••• ",
139 " ",
140 " •• ",
141 " ••• • • ••••• • •••• • • •• •• •• ",
142 " • • • •••••• ••••••••• • •• •• ••• ",
143 "• ••• •••• •••• • • • ••• • • ••• •",
144 " •• • • •• • •• •• ",
145 "• • • ",
146 " ",
147 ]);
148 assert_eq!(buffer, expected);
149 }
150
151 #[test]
152 fn draw_high() {
153 let mut buffer = Buffer::empty(Rect::new(0, 0, 80, 40));
154 let canvas = Canvas::default()
155 .marker(Marker::Braille)
156 .x_bounds([-180.0, 180.0])
157 .y_bounds([-90.0, 90.0])
158 .paint(|context| {
159 context.draw(&Map {
160 resolution: MapResolution::High,
161 ..Default::default()
162 });
163 });
164 canvas.render(buffer.area, &mut buffer);
165 let expected = Buffer::with_lines([
166 " ",
167 " ⢀⣀⣤⠄⠤⠤⣤⣀⡀⣀⣀⡄⠄⢄⣀⣄⡄⢀⡀ ",
168 " ⢀⣀⣤⠰⢤⣼⡯⢽⡟⣀⢶⣺⡛⠁ ⠈⢰⠃⠁ ⢖⣒⣾⡟⠂ ⠈⠛⠁ ⠺⢩⢖⡄ ",
169 " ⡬⢍⣿⣟⣿⣻⣿⣿⣿⡾⣯⡀⠈⠁⠁⢦ ⢀⡿ ⠈ ⢠⢶⠘⠋⡁⣀⢠⠤⠖⠘⠉⠁⠈⠼⡧⡄⣄⡀ ⢫⣗⠒⠆ ",
170 "⣓ ⣠⠖⠓⠒⠢⠤⢄⠤⠶⠽⠽⣶⣃⣽⡮⣿⡷⣗⣤⡭⣍⢓⡄ ⠸⣷ ⢀⣀⠿⠇ ⢀⠔⠒⠲⠄⢄⢀⡀⢙⣑⡄⠴⡍⣟⠉ ⠑⠉⠉ ⠑⠐⠦⠤⣤⠤⢞",
171 "⠶⢧⣗⢾⡆ ⠈⠈⠁⠈⠉⢀⣹⣶⣩⣽⣐⢮⠃ ⣇ ⢀⡔⠊ ⢰⣖⣲ ⢀⡐⠁⣰⠦ ⢲⣶⠛⠋ ⠐⠋ ⡤",
172 " ⠉⣮⣀⣀⣴⡤⣠⡀ ⡎ ⠛⢫⠙⢫⢫ ⠈⠦⠼ ⡃⡀⢸⠼⣤⡄ ⡀⣀⣀⡐⡶⣣⢤⠖⠉",
173 " ⢀⡽⠟⠃ ⠈⠱⡀ ⠙⠢⣀⣨⠆⠈⠁⢧⡀ ⣸⣷ ⢹⣷⣼⣸⠃ ⢀⡐⢀ ⠁⡚⣨⠆ ",
174 " ⠘⢳⡀ ⠈⠾ ⣀⣀⣽ ⠸⢼⣇⡧⠋⠉⠁ ⠉⣿ ⠢⠂ ",
175 " ⠈⢻ ⠜⢹⣵⠻⠇ ⠈⢻ ⢀⡀ ⢠⣠⡤ ⢀⢤ ⢰⣯ ",
176 " ⢼ ⢀⣾⠛⠉ ⠐⡖⠒⡰⢺⣞⣵⡄⢀⣏⡭⣙⡄⢕⢫⡀ ⢀ ⢠⠖⢱⡿⠃ ",
177 " ⠸ ⠠⡎ ⠰⣅⣰⣃⣘⡣⡿⢻⡿⣁⣀ ⠸⣽ ⠐⣿⣽⣫ ⡸⡇ ",
178 " ⠳⣄ ⡰⠃ ⢀⠎⠉ ⢧⡀⣠⣛⠈⢻ ⢻⠘⢺⡿⠚⠁ ",
179 " ⢻⣇ ⣠⠲⠖⢲⡇ ⡸ ⠉⠃⠈⠉⣿ ⢰⣆ ⢸ ⠈⠁ ",
180 " ⠈⢿⣆ ⡟ ⣘⣻ ⡸ ⢸⢇ ⠈⠯⢿⡒⠲⡀ ⢀⡀ ⣀⢾ ",
181 " ⠈⢳ ⠸⡀⢳⣠⢾⠉⢹⣦⣤⣀ ⡇ ⡿⡄ ⢰⠃ ⠑⡂ ⢠⠏⢣ ⣼⡮⠁⢈⡀ ",
182 " ⠙⠲⢆⡿⢦⠈⠉⠁⠁ ⡇ ⠱⣇⣀⠼⠃ ⡃⢰⠃ ⠸⢶ ⠘⠄ ⢾⡁ ",
183 " ⠙⣾⣀⡴⡶⢤⣤ ⢳ ⠻⠵⡆ ⠸⣸ ⢸⡳⡤⠃⢀⡾⣿ ",
184 " ⠘⢻⠁ ⠈⠦⣄ ⢧⣀⣀⠤⣀ ⢐⠁ ⠈⠩⠆ ⣘⣧⠁ ⡸⡔⢿ ",
185 " ⡸ ⢨ ⠁ ⠉⡇ ⢀⠎ ⢻⢿⠄⡴⢑⣧⡠⡄ ",
186 " ⡇ ⠈⠋⠦⡄ ⠈⡆ ⢠⠃ ⢏⡇⢧⣼⣾⣧⣽⣿⠶⢤⡀⣤ ",
187 " ⣇ ⠈⡇ ⢸ ⢸ ⠈⠶⣦⣄⣋⣁⡀⠸⣵⢠⣻⠋⠷⣄ ",
188 " ⠰⡀ ⣰⠁ ⢘⠆ ⢸ ⢠⡀ ⠙⠋⢠⠦⡄⣷⠙⠃ ⠙ ",
189 "⠄ ⠣⡀ ⡃ ⢸ ⣸⢡⢾⠆ ⡞⠛⠘⢧⡏⡆ ⠸⠄ ⡤",
190 " ⠱ ⢠⠃ ⠸⡀ ⢸⠁⢸⢨ ⡤⠚ ⠱⡀ ⢦ ⠁",
191 " ⠅ ⡖⠉ ⡇ ⡜ ⠸⠔ ⡇ ⢳ ",
192 " ⡇ ⢀⠃ ⢱⡀ ⢰⠃ ⣇ ⢀⡀ ⢸ ",
193 " ⢀⠃ ⡦⠏ ⠈⠷⠖⠃ ⠾⠴⠊⠁⠹⣦ ⡞ ⣄ ",
194 " ⢸ ⡤⠃ ⠘⢲⠖⠃ ⣽⡆",
195 " ⢸ ⣸⠁ ⠈⠿ ⢀⢼⠏ ",
196 " ⠞ ⡗ ⣄ ⠈⠋ ",
197 " ⢧⡼⡁⠲⠂ ",
198 " ⠙⠉ ",
199 " ⡀ ",
200 " ⣴⠏⠁ ⣀⡤⢤⣀⣀ ⢀⣀⣤⣀⣀⡴⣄⡤⢤⣀⠤⠤⠴⣄⣀⡀ ",
201 " ⣀⣀ ⣠⣿⡍⣆ ⣠⣤⣤⠤⠴⠶⠖⠲⠤⠔⠛⠒⠉ ⠈⠨⣇⠖⠋ ⠈⠉⠓⠢⠤⢄ ",
202 " ⡀ ⣠⠤⠴⠒⠚⠛⠛⠒⠢⠤⠿⠙⠉⠉⠑⢋⣚⣉⠥⠚ ⢀⣀⡠⠟⠁ ⡴⠋ ",
203 " ⠐⠶⣛⣫⡤ ⠐⢏⣀⣤⣤ ⣴⣋⢇⢀⣮⡥ ⣴⠓ ",
204 "⠤⠤⠤⠤⡀⣈⢣⣠⡄ ⠉⠊⠉⠉⠉ ⠈⠓⠆⠤⠤",
205 " ",
206 ]);
207 assert_eq!(buffer, expected);
208 }
209}