From ec30390446b998cba97a25db63b2e3d27db7a12d Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Fri, 22 Nov 2024 14:00:55 -0800 Subject: [PATCH] fix(canvas): round coordinates to nearest grid cell (#1507) Previously the canvas coordinates were rounded towards zero, which causes the rendering to be off by one pixel in some cases. It also meant that pixels at the extreme edges of the canvas can only be drawn if the point was exactly on the edge of the canvas. This commit rounds the coordinates to the nearest integer instead. This may change the output for some apps using Canvas / Charts. --- ratatui-widgets/src/canvas.rs | 21 +- ratatui-widgets/src/canvas/circle.rs | 8 +- ratatui-widgets/src/canvas/line.rs | 30 +-- ratatui-widgets/src/canvas/map.rs | 150 +++++++------- ratatui-widgets/src/canvas/rectangle.rs | 37 ++-- ratatui/tests/widgets_chart.rs | 252 ------------------------ 6 files changed, 124 insertions(+), 374 deletions(-) diff --git a/ratatui-widgets/src/canvas.rs b/ratatui-widgets/src/canvas.rs index 1af9623c..092bbe8d 100644 --- a/ratatui-widgets/src/canvas.rs +++ b/ratatui-widgets/src/canvas.rs @@ -362,6 +362,9 @@ impl<'a, 'b> Painter<'a, 'b> { /// and `[0, height - 1]` respectively. The resolution of the grid is used to convert the /// `(x, y)` coordinates to the location of a point on the grid. /// + /// Points are rounded to the nearest grid cell (with points exactly in the center of a cell + /// rounding up). + /// /// # Examples /// /// ``` @@ -377,7 +380,7 @@ impl<'a, 'b> Painter<'a, 'b> { /// assert_eq!(point, Some((0, 7))); /// /// let point = painter.get_point(1.5, 1.0); - /// assert_eq!(point, Some((1, 3))); + /// assert_eq!(point, Some((2, 4))); /// /// let point = painter.get_point(0.0, 0.0); /// assert_eq!(point, None); @@ -389,20 +392,18 @@ impl<'a, 'b> Painter<'a, 'b> { /// assert_eq!(point, Some((0, 0))); /// ``` pub fn get_point(&self, x: f64, y: f64) -> Option<(usize, usize)> { - let left = self.context.x_bounds[0]; - let right = self.context.x_bounds[1]; - let top = self.context.y_bounds[1]; - let bottom = self.context.y_bounds[0]; + let [left, right] = self.context.x_bounds; + let [bottom, top] = self.context.y_bounds; if x < left || x > right || y < bottom || y > top { return None; } - let width = (self.context.x_bounds[1] - self.context.x_bounds[0]).abs(); - let height = (self.context.y_bounds[1] - self.context.y_bounds[0]).abs(); - if width == 0.0 || height == 0.0 { + let width = right - left; + let height = top - bottom; + if width <= 0.0 || height <= 0.0 { return None; } - let x = ((x - left) * (self.resolution.0 - 1.0) / width) as usize; - let y = ((top - y) * (self.resolution.1 - 1.0) / height) as usize; + let x = ((x - left) * (self.resolution.0 - 1.0) / width).round() as usize; + let y = ((top - y) * (self.resolution.1 - 1.0) / height).round() as usize; Some((x, y)) } diff --git a/ratatui-widgets/src/canvas/circle.rs b/ratatui-widgets/src/canvas/circle.rs index 144281a2..76766196 100644 --- a/ratatui-widgets/src/canvas/circle.rs +++ b/ratatui-widgets/src/canvas/circle.rs @@ -53,10 +53,10 @@ mod tests { .y_bounds([-10.0, 10.0]); canvas.render(buffer.area, &mut buffer); let expected = Buffer::with_lines([ - " ⢀⣠⢤⣀ ", - " ⢰⠋ ⠈⣇", - " ⠘⣆⡀ ⣠⠇", - " ⠉⠉⠁ ", + " ⣀⣀⣀ ", + " ⡞⠁ ⠈⢣", + " ⢇⡀ ⢀⡼", + " ⠉⠉⠉ ", " ", ]); assert_eq!(buffer, expected); diff --git a/ratatui-widgets/src/canvas/line.rs b/ratatui-widgets/src/canvas/line.rs index 2dea94af..3003a6d5 100644 --- a/ratatui-widgets/src/canvas/line.rs +++ b/ratatui-widgets/src/canvas/line.rs @@ -168,7 +168,7 @@ mod tests { " ", " ", " ", - "••••• ", + "•••••• ", ])] #[case::off_grid6(&Line::new(-1.0, -1.0, 10.0, 10.0, Color::Red), [ " •", @@ -238,12 +238,12 @@ mod tests { " ", " ", " ", - " •", - " •• ", - " •• ", - " •• ", - " •• ", - "• ", + " ", + " ••", + " •• ", + " •• ", + " •• ", + "•• ", ])] // dy < dx, x1 > x2 #[case::diagonal2(&Line::new(10.0, 0.0, 0.0, 5.0, Color::Red), [ @@ -251,15 +251,16 @@ mod tests { " ", " ", " ", - "• ", - " •• ", - " •• ", - " •• ", - " •• ", - " •", + " ", + "•• ", + " •• ", + " •• ", + " •• ", + " ••", ])] // dy > dx, y1 < y2 #[case::diagonal3(&Line::new(0.0, 0.0, 5.0, 10.0, Color::Red), [ + " • ", " • ", " • ", " • ", @@ -269,11 +270,9 @@ mod tests { " • ", " • ", "• ", - "• ", ])] // dy > dx, y1 > y2 #[case::diagonal4(&Line::new(0.0, 10.0, 5.0, 0.0, Color::Red), [ - "• ", "• ", " • ", " • ", @@ -283,6 +282,7 @@ mod tests { " • ", " • ", " • ", + " • ", ])] fn tests<'expected_line, ExpectedLines>(#[case] line: &Line, #[case] expected: ExpectedLines) where diff --git a/ratatui-widgets/src/canvas/map.rs b/ratatui-widgets/src/canvas/map.rs index d4731795..7f550975 100644 --- a/ratatui-widgets/src/canvas/map.rs +++ b/ratatui-widgets/src/canvas/map.rs @@ -102,44 +102,44 @@ mod tests { canvas.render(buffer.area, &mut buffer); let expected = Buffer::with_lines([ " ", - " ••••••• •• •• •• • ", - " •••••••••••••• ••• •••• ••• •• •••• ", - " •••••••••••••••• •• ••• ••••••• •• •• ••• ", - "• • •• •••••• •••••••••••• •• ••• • ••••• ••••••••• •• • • • • ", - "••••• •••• •••••••• •• •• ••• •••• •••• •• • • ", - " •••••••• ••••••• ••••• ••• •••••••• • ••••• ", - " •• •• •• ••••••• •• ••• •••• •• • ", - "••• ••• •••••• •••• •••• •• • •• ", - " • ••••••••• •• • ••• • •• •• •• ", - " • • •••• •• ••••••••• ••• • • • •• ", - " • • ••••• •••• •• •••••• ", - " • •• • • •• • ••••• ", - " •• •• • • •• •• • ", - " •• ••• ••• • • ••••• • ••• ", - " • •••• ••• • • • • • •• ", - " •••• • • •• • • •• •• ", - " ••• •• • • • •• ••• ••• ", - " • • • •• • • • • • ", - " • • • • • • ••• • • ", - " • • • • •• • • • ", - " • • •• ••• • ", - " • • • • • • • • ", - " • • • •• • • • • • ", - " • • • • ", - " • • • • • • ", - " • •• • • • • •• • ", - " • • • •••• •• ", - " • • •• ••• ", - " •• • ", - " •• • ", - " •• ", + " • ", + " • •• •••••••• •• •••• ••••• ••• •• ••• ", + " ••••••••••••••• • •••• • • ••••••• ••• ", + " • •••• ••••••••••••••• •• •• • ••• •• •••• •• ••••••• ••• ", + "••••• •••••••••••• •••• • •••••• •••• • ••• ••••• •", + " •• • • •••• •••••••• •••• •• • •• • ••• •• •••", + " •••• ••• •••••• ••••• • •• •••••• • ••••• ", + "••••• ••• • •• •• ••••••• •• •• •• ", + " •• •••• ••••• •• • • • •• ", + " • • ••••••• •• •••• ••• •• • •• • •• ", + " • •• ••••••••• • •• •••• • ", + " •• •• • • • •• • ••••• ", + " •• ••• • •••• • • • ", + " • • •• • •• •• • • ", + " •• • ••••••• • • • • • •• • ", + " ••••••••• • •• • • • •• • •• ", + " •• •• • ••• • ••• •• ", + " ••• • • • • • •• ••• ••• ", + " • • •• • •• ", + " • • ••• • • ••• ••• ", + " • • • • • ••• ", + " • • • • • • • ", + " • • • • ••• •• •", + " • • • • •• • • • ", + " • • • • • ", + " • • • • • ", + " •• •• •• •• • • ", + " • • ••• •• ", + " • • •• •• ", + " • • ", + " ••••• ", " ", - " ••• • •••• • • •• • ", - " •••• •••••• •••••• •••••• • ••• ", - " •• •••••• ••••• •• • ••• • •• ", - "• ••••• •• •• •••••• • •• ", - "• • • • • • • ", - " • ", + " •• ", + " ••• • • ••••• • •••• • • •• •• •• ", + " • • • •••••• ••••••••• • •• •• ••• ", + "• ••• •••• •••• • • • ••• • • ••• •", + " •• • • •• • •• •• ", + "• • • ", " ", ]); assert_eq!(buffer, expected); @@ -161,44 +161,44 @@ mod tests { canvas.render(buffer.area, &mut buffer); let expected = Buffer::with_lines([ " ", - " ⢀⣠⠤⠤⠤⠔⢤⣤⡄⠤⡠⣄⠢⠂⢢⠰⣠⡄⣀⡀ ⣀ ", - " ⢀⣀⡤⣦⠲⢶⣿⣮⣿⡉⣰⢶⢏⡂ ⢀⣟⠁ ⢺⣻⢿⠏ ⠈⠉⠁ ⢀⣀ ⠈⠓⢳⣢⣂⡀ ", - " ⡞⣳⣿⣻⡧⣷⣿⣿⢿⢿⣧⡀⠉⠉⠙⢆ ⣰⠇ ⣠⠞⠃⢉⣄⣀⣠⠴⠊⠉⠁ ⠐⠾⠤⢤⠤⡄⠐⣻⠜⢓⠂ ", - "⢍ ⢀⡴⠊⠙⠓⠒⠒⠤⠖⠺⠿⠽⣷⣬⢬⣾⣷⢻⣷⢲⢲⣍⠱⡀ ⠹⡗ ⢀⢐⠟ ⡔⠒⠉⠲⠤⢀⢄⡀⢩⣣⠦⢷⢼⡏⠈ ⠉⠉⠉ ⠈⠈⠉⠖⠤⠆⠒⠭", - "⠶⢽⡲⣽⡆ ⠈⣠⣽⣯⡼⢯⣘⡯⠃⠘⡆ ⢰⠒⠁ ⢾⣚⠟ ⢀⠆ ⣔⠆ ⢷⠾⠋⠁ ⠙⠁ ⠠⡤", - " ⠠⢧⣄⣀⡶⠦⠤⡀ ⢰⡁ ⠉⡻⠙⣎⡥ ⠘⠲⠇ ⢀⡀⠨⣁⡄⣸⢫⡤⠄ ⣀⢠⣤⠊⣼⠅⠖⠋⠁", - " ⣠⠾⠛⠁ ⠈⣱ ⠋⠦⢤⡼ ⠈⠈⠦⡀ ⢀⣿⣇ ⢹⣷⣂⡞⠃ ⢀⣂⡀ ⠏⣜ ", - " ⠙⣷⡄ ⠘⠆ ⢀⣀⡠⣗ ⠘⣻⣽⡟⠉⠈ ⢹⡇ ⠟⠁ ", - " ⠈⡟ ⢎⣻⡿⠾⠇ ⠘⠇ ⣀⡀ ⣤⣤⡆ ⡠⡦ ⢀⠎⡏ ", - " ⡇ ⣀⠏⠋ ⢸⠒⢃⡖⢻⢟⣷⣄⣰⣡⠥⣱ ⢏⣧ ⣀ ⡴⠚⢰⠟ ", - " ⢳ ⢸⠃ ⠸⣄⣼⣠⢼⡴⡟⢿⢿⣀⣄ ⠸⡹ ⠘⡯⢿⡇⡠⢼⠁ ", - " ⢳⣀ ⢀⠞⠁ ⢠⠋⠁ ⠐⠧⡄⣬⣉⣈⡽ ⢧⠘⢽⠟⠉ ", - " ⣿⣄ ⡴⠚⠛⣿⣀ ⢠⠖ ⠈⠁ ⠹⣧ ⢾⣄⡀ ⡼ ⠈ ", - " ⣀ ⠘⣿⡄ ⡇ ⣘⣻ ⡏ ⢻⡄ ⠘⠿⢿⠒⠲⡀ ⢀⡀ ⢀⡰⣗ ", - " ⠉⠷ ⢫⡀⢧⡼⡟⠉⣛⣳⣦⡀ ⠈⡇ ⠸⣱ ⢀⡼ ⢺ ⡸⠉⢇ ⣾⡏ ⣁ ", - " ⠉⠒⢆⡓⡆ ⠠⡃ ⢳⣇⡠⠏ ⠐⡄⡞ ⠘⣇⡀⢱ ⣾⡀ ", - " ⢹⣇⣀⣾⡷⠤⡆ ⢣ ⠯⢺⠇ ⢣⣅ ⣽⢱⡔ ⢠⢿⣗ ", - " ⠙⢱ ⠘⠦⡄ ⠈⢦⡠⣠⢶⣀ ⡜ ⠈⠿ ⢠⣽⢆ ⢀⣼⡜⠿ ", - " ⢀⡞ ⢱⡀ ⢸ ⡔⠁ ⢻⢿⢰⠏⢸⣤⣴⣆ ", - " ⢘⠆ ⠙⠢⢄ ⠸⡀ ⡸⠁ ⠈⣞⡎⠥⡟⣿⠠⠿⣷⠒⢤⢀⣆ ", - " ⠘⠆ ⢈⠂ ⢳ ⡇ ⠈⠳⠶⣤⣭⣠ ⠋⢧⡬⣟⠉⠷⡄ ", - " ⢨ ⡜ ⢸ ⠸ ⣠ ⠁⢁⣰⢶ ⡇⠉⠁ ⠛ ", - "⠆ ⠈⢱⡀ ⡆ ⡇ ⢀⡜⡴⢹ ⢰⠏⠁⠘⢶⠹⡀ ⠸ ⢠⡶", - " ⠅ ⣸ ⢸ ⢫ ⡞⡊ ⢠⠔⠋ ⢳⡀ ⠐⣦ ", - " ⡅ ⡏ ⠈⡆ ⢠⠎ ⠳⠃ ⢸ ⢳ ", - " ⠨ ⡸⠁ ⢱ ⡸ ⠈⡇ ⢀⣀⡀ ⢸ ", - " ⠸ ⠐⡶⠁ ⠘⠖⠚ ⠣⠒⠋ ⠱⣇ ⢀⠇ ⠰⡄ ", - " ⠽ ⣰⡖⠁ ⠘⢚⡊ ⢀⣿⠇", - " ⡯⢀⡟ ⠘⠏ ⢠⢾⠃ ", - " ⠇⢨⠆ ⢠⡄ ⠈⠁ ", - " ⢧⣷⡀⠚ ", - " ⠉⠁ ", - " ⢀⡀ ", - " ⢠⡾⠋ ⣀⡠⠖⢦⣀⣀ ⣀⠤⠦⢤⠤⠶⠤⠖⠦⠤⠤⠤⠴⠤⢤⣄ ", - " ⢀⣤⣀ ⡀ ⣼⣻⠙⡆ ⢀⡤⠤⠤⠴⠒⠖⠒⠒⠒⠚⠉⠋⠁ ⢰⡳⠊⠁ ⠈⠉⠉⠒⠤⣤ ", - " ⢀⣀⣀⡴⠖⠒⠒⠚⠛⠛⠛⠒⠚⠳⠉⠉⠉⠉⢉⣉⡥⠔⠃ ⢀⣠⠤⠴⠃ ⢠⠞⠁ ", - " ⠘⠛⣓⣒⠆ ⠸⠥⣀⣤⡦⠠⣞⣭⣇⣘⠿⠆ ⣖⠛ ", - "⠶⠔⠲⠤⠠⠜⢗⠤⠄ ⠘⠉ ⠁ ⠈⠉⠒⠔⠤", + " ⢀⣀⣤⠄⠤⠤⣤⣀⡀⣀⣀⡄⠄⢄⣀⣄⡄⢀⡀ ", + " ⢀⣀⣤⠰⢤⣼⡯⢽⡟⣀⢶⣺⡛⠁ ⠈⢰⠃⠁ ⢖⣒⣾⡟⠂ ⠈⠛⠁ ⠺⢩⢖⡄ ", + " ⡬⢍⣿⣟⣿⣻⣿⣿⣿⡾⣯⡀⠈⠁⠁⢦ ⢀⡿ ⠈ ⢠⢶⠘⠋⡁⣀⢠⠤⠖⠘⠉⠁⠈⠼⡧⡄⣄⡀ ⢫⣗⠒⠆ ", + "⣓ ⣠⠖⠓⠒⠢⠤⢄⠤⠶⠽⠽⣶⣃⣽⡮⣿⡷⣗⣤⡭⣍⢓⡄ ⠸⣷ ⢀⣀⠿⠇ ⢀⠔⠒⠲⠄⢄⢀⡀⢙⣑⡄⠴⡍⣟⠉ ⠑⠉⠉ ⠑⠐⠦⠤⣤⠤⢞", + "⠶⢧⣗⢾⡆ ⠈⠈⠁⠈⠉⢀⣹⣶⣩⣽⣐⢮⠃ ⣇ ⢀⡔⠊ ⢰⣖⣲ ⢀⡐⠁⣰⠦ ⢲⣶⠛⠋ ⠐⠋ ⡤", + " ⠉⣮⣀⣀⣴⡤⣠⡀ ⡎ ⠛⢫⠙⢫⢫ ⠈⠦⠼ ⡃⡀⢸⠼⣤⡄ ⡀⣀⣀⡐⡶⣣⢤⠖⠉", + " ⢀⡽⠟⠃ ⠈⠱⡀ ⠙⠢⣀⣨⠆⠈⠁⢧⡀ ⣸⣷ ⢹⣷⣼⣸⠃ ⢀⡐⢀ ⠁⡚⣨⠆ ", + " ⠘⢳⡀ ⠈⠾ ⣀⣀⣽ ⠸⢼⣇⡧⠋⠉⠁ ⠉⣿ ⠢⠂ ", + " ⠈⢻ ⠜⢹⣵⠻⠇ ⠈⢻ ⢀⡀ ⢠⣠⡤ ⢀⢤ ⢰⣯ ", + " ⢼ ⢀⣾⠛⠉ ⠐⡖⠒⡰⢺⣞⣵⡄⢀⣏⡭⣙⡄⢕⢫⡀ ⢀ ⢠⠖⢱⡿⠃ ", + " ⠸ ⠠⡎ ⠰⣅⣰⣃⣘⡣⡿⢻⡿⣁⣀ ⠸⣽ ⠐⣿⣽⣫ ⡸⡇ ", + " ⠳⣄ ⡰⠃ ⢀⠎⠉ ⢧⡀⣠⣛⠈⢻ ⢻⠘⢺⡿⠚⠁ ", + " ⢻⣇ ⣠⠲⠖⢲⡇ ⡸ ⠉⠃⠈⠉⣿ ⢰⣆ ⢸ ⠈⠁ ", + " ⠈⢿⣆ ⡟ ⣘⣻ ⡸ ⢸⢇ ⠈⠯⢿⡒⠲⡀ ⢀⡀ ⣀⢾ ", + " ⠈⢳ ⠸⡀⢳⣠⢾⠉⢹⣦⣤⣀ ⡇ ⡿⡄ ⢰⠃ ⠑⡂ ⢠⠏⢣ ⣼⡮⠁⢈⡀ ", + " ⠙⠲⢆⡿⢦⠈⠉⠁⠁ ⡇ ⠱⣇⣀⠼⠃ ⡃⢰⠃ ⠸⢶ ⠘⠄ ⢾⡁ ", + " ⠙⣾⣀⡴⡶⢤⣤ ⢳ ⠻⠵⡆ ⠸⣸ ⢸⡳⡤⠃⢀⡾⣿ ", + " ⠘⢻⠁ ⠈⠦⣄ ⢧⣀⣀⠤⣀ ⢐⠁ ⠈⠩⠆ ⣘⣧⠁ ⡸⡔⢿ ", + " ⡸ ⢨ ⠁ ⠉⡇ ⢀⠎ ⢻⢿⠄⡴⢑⣧⡠⡄ ", + " ⡇ ⠈⠋⠦⡄ ⠈⡆ ⢠⠃ ⢏⡇⢧⣼⣾⣧⣽⣿⠶⢤⡀⣤ ", + " ⣇ ⠈⡇ ⢸ ⢸ ⠈⠶⣦⣄⣋⣁⡀⠸⣵⢠⣻⠋⠷⣄ ", + " ⠰⡀ ⣰⠁ ⢘⠆ ⢸ ⢠⡀ ⠙⠋⢠⠦⡄⣷⠙⠃ ⠙ ", + "⠄ ⠣⡀ ⡃ ⢸ ⣸⢡⢾⠆ ⡞⠛⠘⢧⡏⡆ ⠸⠄ ⡤", + " ⠱ ⢠⠃ ⠸⡀ ⢸⠁⢸⢨ ⡤⠚ ⠱⡀ ⢦ ⠁", + " ⠅ ⡖⠉ ⡇ ⡜ ⠸⠔ ⡇ ⢳ ", + " ⡇ ⢀⠃ ⢱⡀ ⢰⠃ ⣇ ⢀⡀ ⢸ ", + " ⢀⠃ ⡦⠏ ⠈⠷⠖⠃ ⠾⠴⠊⠁⠹⣦ ⡞ ⣄ ", + " ⢸ ⡤⠃ ⠘⢲⠖⠃ ⣽⡆", + " ⢸ ⣸⠁ ⠈⠿ ⢀⢼⠏ ", + " ⠞ ⡗ ⣄ ⠈⠋ ", + " ⢧⡼⡁⠲⠂ ", + " ⠙⠉ ", + " ⡀ ", + " ⣴⠏⠁ ⣀⡤⢤⣀⣀ ⢀⣀⣤⣀⣀⡴⣄⡤⢤⣀⠤⠤⠴⣄⣀⡀ ", + " ⣀⣀ ⣠⣿⡍⣆ ⣠⣤⣤⠤⠴⠶⠖⠲⠤⠔⠛⠒⠉ ⠈⠨⣇⠖⠋ ⠈⠉⠓⠢⠤⢄ ", + " ⡀ ⣠⠤⠴⠒⠚⠛⠛⠒⠢⠤⠿⠙⠉⠉⠑⢋⣚⣉⠥⠚ ⢀⣀⡠⠟⠁ ⡴⠋ ", + " ⠐⠶⣛⣫⡤ ⠐⢏⣀⣤⣤ ⣴⣋⢇⢀⣮⡥ ⣴⠓ ", + "⠤⠤⠤⠤⡀⣈⢣⣠⡄ ⠉⠊⠉⠉⠉ ⠈⠓⠆⠤⠤", " ", ]); assert_eq!(buffer, expected); diff --git a/ratatui-widgets/src/canvas/rectangle.rs b/ratatui-widgets/src/canvas/rectangle.rs index 35746eda..9ee35c87 100644 --- a/ratatui-widgets/src/canvas/rectangle.rs +++ b/ratatui-widgets/src/canvas/rectangle.rs @@ -149,42 +149,43 @@ mod tests { let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 10)); let canvas = Canvas::default() .marker(Marker::Braille) - .x_bounds([0.0, 10.0]) - .y_bounds([0.0, 10.0]) + .x_bounds([0.0, 20.0]) + .y_bounds([0.0, 20.0]) .paint(|context| { // a rectangle that will draw the outside part of the braille context.draw(&Rectangle { x: 0.0, y: 0.0, - width: 10.0, - height: 10.0, + width: 20.0, + height: 20.0, color: Color::Red, }); // a rectangle that will draw the inside part of the braille context.draw(&Rectangle { - x: 2.0, - y: 1.75, - width: 6.5, - height: 6.5, + x: 4.0, + y: 4.0, + width: 12.0, + height: 12.0, color: Color::Green, }); }); canvas.render(buffer.area, &mut buffer); let mut expected = Buffer::with_lines([ "⡏⠉⠉⠉⠉⠉⠉⠉⠉⢹", - "⡇⢠⠤⠤⠤⠤⠤⠤⡄⢸", - "⡇⢸ ⡇⢸", - "⡇⢸ ⡇⢸", - "⡇⢸ ⡇⢸", - "⡇⢸ ⡇⢸", - "⡇⢸ ⡇⢸", - "⡇⢸ ⡇⢸", - "⡇⠈⠉⠉⠉⠉⠉⠉⠁⢸", + "⡇ ⢸", + "⡇ ⡏⠉⠉⠉⠉⢹ ⢸", + "⡇ ⡇ ⢸ ⢸", + "⡇ ⡇ ⢸ ⢸", + "⡇ ⡇ ⢸ ⢸", + "⡇ ⡇ ⢸ ⢸", + "⡇ ⣇⣀⣀⣀⣀⣸ ⢸", + "⡇ ⢸", "⣇⣀⣀⣀⣀⣀⣀⣀⣀⣸", ]); expected.set_style(buffer.area, Style::new().red()); - expected.set_style(buffer.area.inner(Margin::new(1, 1)), Style::new().green()); - expected.set_style(buffer.area.inner(Margin::new(2, 2)), Style::reset()); + expected.set_style(buffer.area.inner(Margin::new(1, 1)), Style::reset()); + expected.set_style(buffer.area.inner(Margin::new(2, 2)), Style::new().green()); + expected.set_style(buffer.area.inner(Margin::new(3, 3)), Style::reset()); assert_eq!(buffer, expected); } } diff --git a/ratatui/tests/widgets_chart.rs b/ratatui/tests/widgets_chart.rs index 408bda85..b66e146c 100644 --- a/ratatui/tests/widgets_chart.rs +++ b/ratatui/tests/widgets_chart.rs @@ -365,258 +365,6 @@ fn widgets_chart_can_have_empty_datasets() { .unwrap(); } -#[allow(clippy::too_many_lines)] -#[test] -fn widgets_chart_can_have_a_legend() { - let backend = TestBackend::new(60, 30); - let mut terminal = Terminal::new(backend).unwrap(); - terminal - .draw(|f| { - let datasets = vec![ - Dataset::default() - .name("Dataset 1") - .style(Style::default().fg(Color::Blue)) - .data(&[ - (0.0, 0.0), - (10.0, 1.0), - (20.0, 2.0), - (30.0, 3.0), - (40.0, 4.0), - (50.0, 5.0), - (60.0, 6.0), - (70.0, 7.0), - (80.0, 8.0), - (90.0, 9.0), - (100.0, 10.0), - ]) - .graph_type(Line), - Dataset::default() - .name("Dataset 2") - .style(Style::default().fg(Color::Green)) - .data(&[ - (0.0, 10.0), - (10.0, 9.0), - (20.0, 8.0), - (30.0, 7.0), - (40.0, 6.0), - (50.0, 5.0), - (60.0, 4.0), - (70.0, 3.0), - (80.0, 2.0), - (90.0, 1.0), - (100.0, 0.0), - ]) - .graph_type(Line), - ]; - let chart = Chart::new(datasets) - .style(Style::default().bg(Color::White)) - .block(Block::bordered().title("Chart Test")) - .x_axis( - Axis::default() - .bounds([0.0, 100.0]) - .title(Span::styled("X Axis", Style::default().fg(Color::Yellow))) - .labels(create_labels(&["0.0", "50.0", "100.0"])), - ) - .y_axis( - Axis::default() - .bounds([0.0, 10.0]) - .title("Y Axis") - .labels(create_labels(&["0.0", "5.0", "10.0"])), - ); - f.render_widget( - chart, - Rect { - x: 0, - y: 0, - width: 60, - height: 30, - }, - ); - }) - .unwrap(); - let mut expected = Buffer::with_lines([ - "┌Chart Test────────────────────────────────────────────────┐", - "│10.0│Y Axis ┌─────────┐│", - "│ │ •• │Dataset 1││", - "│ │ •• │Dataset 2││", - "│ │ •• └─────────┘│", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ ••• •• │", - "│ │ ••• │", - "│5.0 │ •• •• │", - "│ │ •• •• │", - "│ │ ••• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│ │ •• ••• │", - "│ │ •• •• │", - "│ │ •• •• │", - "│0.0 │• X Axis│", - "│ └─────────────────────────────────────────────────────│", - "│ 0.0 50.0 100.0│", - "└──────────────────────────────────────────────────────────┘", - ]); - - // Set expected background color - for row in 0..30 { - for col in 0..60 { - expected[(col, row)].set_bg(Color::White); - } - } - - // Set expected colors of the first dataset - let line1 = vec![ - (48, 5), - (49, 5), - (46, 6), - (47, 6), - (44, 7), - (45, 7), - (42, 8), - (43, 8), - (40, 9), - (41, 9), - (38, 10), - (39, 10), - (36, 11), - (37, 11), - (34, 12), - (35, 12), - (33, 13), - (30, 14), - (31, 14), - (28, 15), - (29, 15), - (25, 16), - (26, 16), - (27, 16), - (23, 17), - (24, 17), - (21, 18), - (22, 18), - (19, 19), - (20, 19), - (17, 20), - (18, 20), - (15, 21), - (16, 21), - (13, 22), - (14, 22), - (11, 23), - (12, 23), - (9, 24), - (10, 24), - (7, 25), - (8, 25), - (6, 26), - ]; - let legend1 = vec![ - (49, 2), - (50, 2), - (51, 2), - (52, 2), - (53, 2), - (54, 2), - (55, 2), - (56, 2), - (57, 2), - ]; - for (col, row) in line1 { - expected[(col, row)].set_fg(Color::Blue); - } - for (col, row) in legend1 { - expected[(col, row)].set_fg(Color::Blue); - } - - // Set expected colors of the second dataset - let line2 = vec![ - (8, 2), - (9, 2), - (10, 3), - (11, 3), - (12, 4), - (13, 4), - (14, 5), - (15, 5), - (16, 6), - (17, 6), - (18, 7), - (19, 7), - (20, 8), - (21, 8), - (22, 9), - (23, 9), - (24, 10), - (25, 10), - (26, 11), - (27, 11), - (28, 12), - (29, 12), - (30, 12), - (31, 13), - (32, 13), - (33, 14), - (34, 14), - (35, 15), - (36, 15), - (37, 16), - (38, 16), - (39, 17), - (40, 17), - (41, 18), - (42, 18), - (43, 19), - (44, 19), - (45, 20), - (46, 20), - (47, 21), - (48, 21), - (49, 22), - (50, 22), - (51, 23), - (52, 23), - (53, 23), - (54, 24), - (55, 24), - (56, 25), - (57, 25), - ]; - let legend2 = vec![ - (49, 3), - (50, 3), - (51, 3), - (52, 3), - (53, 3), - (54, 3), - (55, 3), - (56, 3), - (57, 3), - ]; - for (col, row) in line2 { - expected[(col, row)].set_fg(Color::Green); - } - for (col, row) in legend2 { - expected[(col, row)].set_fg(Color::Green); - } - - // Set expected colors of the x axis - let x_axis_title = vec![(53, 26), (54, 26), (55, 26), (56, 26), (57, 26), (58, 26)]; - for (col, row) in x_axis_title { - expected[(col, row)].set_fg(Color::Yellow); - } - terminal.backend().assert_buffer(&expected); -} - #[test] fn widgets_chart_top_line_styling_is_correct() { let backend = TestBackend::new(9, 5);