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}