dioxus_mind_elixir/
interact.rs1use crate::MindMapError;
3
4#[derive(Clone, Copy, Debug, Default, PartialEq)]
6pub struct Point {
7 pub x: f64,
9 pub y: f64,
11}
12#[derive(Clone, Copy, Debug, PartialEq)]
14pub struct Viewport {
15 pub translation: Point,
17 pub scale: f64,
19}
20impl Default for Viewport {
21 fn default() -> Self {
22 Self {
23 translation: Point::default(),
24 scale: 1.0,
25 }
26 }
27}
28impl Viewport {
29 pub fn to_canvas(self, point: Point) -> Result<Point, MindMapError> {
31 self.validate()?;
32 if !point.x.is_finite() || !point.y.is_finite() {
33 return Err(MindMapError::InvalidGeometry);
34 }
35 let result = Point {
36 x: (point.x - self.translation.x) / self.scale,
37 y: (point.y - self.translation.y) / self.scale,
38 };
39 if !result.x.is_finite() || !result.y.is_finite() {
40 return Err(MindMapError::InvalidGeometry);
41 }
42 Ok(result)
43 }
44 pub fn zoom_at(&mut self, scale: f64, anchor: Point) -> Result<(), MindMapError> {
46 let canvas = self.to_canvas(anchor)?;
47 if !scale.is_finite() {
48 return Err(MindMapError::InvalidGeometry);
49 }
50 let scale = scale.clamp(0.1, 4.0);
51 let translation = Point {
52 x: anchor.x - canvas.x * scale,
53 y: anchor.y - canvas.y * scale,
54 };
55 if !translation.x.is_finite() || !translation.y.is_finite() {
56 return Err(MindMapError::InvalidGeometry);
57 }
58 self.translation = translation;
59 self.scale = scale;
60 Ok(())
61 }
62 pub fn pan(&mut self, delta: Point) -> Result<(), MindMapError> {
64 self.validate()?;
65 let translation = Point {
66 x: self.translation.x + delta.x,
67 y: self.translation.y + delta.y,
68 };
69 if !translation.x.is_finite() || !translation.y.is_finite() {
70 return Err(MindMapError::InvalidGeometry);
71 }
72 self.translation = translation;
73 Ok(())
74 }
75 pub fn center(&mut self, target: Point, size: Point) -> Result<(), MindMapError> {
77 self.validate()?;
78 if ![target.x, target.y, size.x, size.y]
79 .into_iter()
80 .all(f64::is_finite)
81 || size.x <= 0.0
82 || size.y <= 0.0
83 {
84 return Err(MindMapError::InvalidGeometry);
85 }
86 let translation = Point {
87 x: size.x / 2.0 - target.x * self.scale,
88 y: size.y / 2.0 - target.y * self.scale,
89 };
90 if !translation.x.is_finite() || !translation.y.is_finite() {
91 return Err(MindMapError::InvalidGeometry);
92 }
93 self.translation = translation;
94 Ok(())
95 }
96 pub fn validate(self) -> Result<(), MindMapError> {
98 if [self.translation.x, self.translation.y, self.scale]
99 .into_iter()
100 .all(f64::is_finite)
101 && (0.1..=4.0).contains(&self.scale)
102 {
103 Ok(())
104 } else {
105 Err(MindMapError::InvalidGeometry)
106 }
107 }
108}