From b8e501b7d4d3991669233109a6f8213a2d624c14 Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Sat, 20 Jan 2024 23:29:49 +0100 Subject: add graph labels and step resizing on zooming --- src/ui/graph.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 15 deletions(-) (limited to 'src/ui') diff --git a/src/ui/graph.rs b/src/ui/graph.rs index 2f3855d..13e8ac9 100644 --- a/src/ui/graph.rs +++ b/src/ui/graph.rs @@ -4,7 +4,7 @@ use super::Message; use iced::{ event, mouse::{self, Interaction}, - widget::canvas::{self, stroke, Cache, Frame, Geometry, LineCap, Path, Stroke}, + widget::canvas::{self, stroke, Cache, Frame, Geometry, LineCap, Path, Stroke, Text}, Color, Point, Rectangle, Renderer, Size, Theme, Vector, }; @@ -45,12 +45,22 @@ pub struct GraphState { } impl GraphState { - fn view_rectangle(&self, frame: &Frame) -> Rectangle { - let s = Size::new(frame.width() / self.scale + 2.0, frame.height() / self.scale + 2.0); - let p = Point::new(-self.center.x / self.scale - s.width / 2.0, -self.center.y / self.scale - s.height / 2.0); + fn view_rectangle(&self, frame: &Frame, step: usize) -> Rectangle { + let s = Size::new( + self.map_to_step(frame.width() / self.scale + 2.0 * step as f32, step), + self.map_to_step(frame.height() / self.scale + 2.0 * step as f32, step), + ); + let p = Point::new( + self.map_to_step(-self.center.x / self.scale - s.width / 2.0, step), + self.map_to_step(-self.center.y / self.scale - s.height / 2.0, step), + ); Rectangle::new(p, s) } + fn map_to_step(&self, n: f32, step: usize) -> f32 { + ((n as i64 / step as i64) * step as i64) as f32 + } + fn map_coords(&self, x: f32, y: f32) -> Point { Point::new(x, -y) } @@ -79,37 +89,43 @@ impl canvas::Program for GraphCanvas { _cursor: mouse::Cursor, ) -> Vec { let graph = self.graph.draw(renderer, bounds.size(), |frame| { + let zcolor = Color::new(0.27, 0.52, 0.53, 1.0); + let lcolor = Color::new(0.49, 0.43, 0.39, 1.0); + let gcolor = Color::new(0.8, 0.14, 0.11, 1.0); + let step = 10_usize.pow((400.0 / state.scale).log10() as u32); + let unitline_whole = Stroke { width: 1.0, - style: stroke::Style::Solid(Color::new(0.5, 0.5, 0.5, 1.0)), + style: stroke::Style::Solid(lcolor), line_cap: LineCap::Round, ..Stroke::default() }; + let zeroline = Stroke { width: 3.0, - style: stroke::Style::Solid(Color::new(0.0, 0.0, 0.8, 1.0)), + style: stroke::Style::Solid(zcolor), line_cap: LineCap::Round, ..Stroke::default() }; let graphline = Stroke { width: 3.0, - style: stroke::Style::Solid(Color::new(0.8, 0.0, 0.0, 1.0)), + style: stroke::Style::Solid(gcolor), line_cap: LineCap::Round, ..Stroke::default() }; + let rect = state.view_rectangle(frame, step); + let x_end = (rect.x + rect.width) as i64; + let y_end = (rect.y + rect.height) as i64; + frame.translate(Vector { x: frame.center().x + state.center.x, y: frame.center().y + state.center.y, }); frame.scale(state.scale); - let rect = state.view_rectangle(frame); - let x_end = (rect.x + rect.width) as i64; - let y_end = (rect.y + rect.height) as i64; - - for y in (rect.y as i64..y_end).step_by(1) { + for y in (rect.y as i64..y_end).step_by(step) { let line = Path::line( Point::new(rect.x, y as f32), Point::new(rect.x + rect.width, y as f32), @@ -117,7 +133,7 @@ impl canvas::Program for GraphCanvas { frame.stroke(&line, unitline_whole.clone()); } - for x in (rect.x as i64..x_end).step_by(1) { + for x in (rect.x as i64..x_end).step_by(step) { let line = Path::line( Point::new(x as f32, rect.y), Point::new(x as f32, rect.y + rect.height), @@ -142,8 +158,35 @@ impl canvas::Program for GraphCanvas { ); frame.with_save(|frame| { - frame.translate(Vector { x: 1.0, y: 0.0 }); - frame.fill_text("1"); + for x in (rect.x as i64..x_end).step_by(step) { + let p = Point::new(x as f32, 0.0); + frame.fill(&Path::circle(p, 10.0 / state.scale), zcolor); + frame.fill_text(Text { + content: x.to_string(), + position: p, + horizontal_alignment: iced::alignment::Horizontal::Center, + vertical_alignment: iced::alignment::Vertical::Center, + color: Color::WHITE, + ..Text::default() + }); + } + + for y in (rect.y as i64..y_end).step_by(step) { + if y == 0 { + continue; + } + + let p = Point::new(0.0, y as f32); + frame.fill(&Path::circle(p, 10.0 / state.scale), zcolor); + frame.fill_text(Text { + content: (-y).to_string(), + position: p, + horizontal_alignment: iced::alignment::Horizontal::Center, + vertical_alignment: iced::alignment::Vertical::Center, + color: Color::WHITE, + ..Text::default() + }); + } }); let mut y1 = self -- cgit v1.2.3-70-g09d2