Skip to main content

neco_view2d_wasm/
lib.rs

1use neco_view2d::View2d;
2use wasm_bindgen::prelude::*;
3
4#[wasm_bindgen]
5pub struct WasmView2d {
6    inner: View2d,
7}
8
9impl Default for WasmView2d {
10    fn default() -> Self {
11        Self::new()
12    }
13}
14
15#[wasm_bindgen]
16impl WasmView2d {
17    #[wasm_bindgen(constructor)]
18    pub fn new() -> Self {
19        Self {
20            inner: View2d::default(),
21        }
22    }
23
24    pub fn pan(&mut self, dx: f64, dy: f64, canvas_height: f64) {
25        self.inner.pan(dx, dy, canvas_height);
26    }
27
28    pub fn zoom_at(&mut self, delta: f64, cx: f64, cy: f64, cw: f64, ch: f64) {
29        self.inner.zoom_at(delta, cx, cy, cw, ch);
30    }
31
32    pub fn canvas_to_world(&self, cx: f64, cy: f64, cw: f64, ch: f64) -> Vec<f64> {
33        let (wx, wy) = self.inner.canvas_to_world(cx, cy, cw, ch);
34        vec![wx, wy]
35    }
36
37    pub fn world_to_canvas(&self, wx: f64, wy: f64, cw: f64, ch: f64) -> Vec<f64> {
38        let (cx, cy) = self.inner.world_to_canvas(wx, wy, cw, ch);
39        vec![cx, cy]
40    }
41
42    pub fn get_state(&self) -> Vec<f64> {
43        vec![
44            self.inner.center_x,
45            self.inner.center_y,
46            self.inner.view_size,
47        ]
48    }
49
50    pub fn set_state(&mut self, cx: f64, cy: f64, vs: f64) {
51        self.inner.set(cx, cy, vs);
52    }
53
54    pub fn fit(&mut self, ww: f64, wh: f64, cw: f64, ch: f64) {
55        self.inner.fit(ww, wh, cw, ch);
56    }
57
58    pub fn zoom_factor(&self, reference_view_size: f64) -> f64 {
59        self.inner.zoom_factor(reference_view_size)
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use neco_view2d::View2d;
67
68    const EPS: f64 = 1e-10;
69
70    fn assert_vec2_close(actual: Vec<f64>, expected: (f64, f64)) {
71        assert_eq!(actual.len(), 2);
72        assert!((actual[0] - expected.0).abs() < EPS);
73        assert!((actual[1] - expected.1).abs() < EPS);
74    }
75
76    fn assert_vec3_close(actual: Vec<f64>, expected: (f64, f64, f64)) {
77        assert_eq!(actual.len(), 3);
78        assert!((actual[0] - expected.0).abs() < EPS);
79        assert!((actual[1] - expected.1).abs() < EPS);
80        assert!((actual[2] - expected.2).abs() < EPS);
81    }
82
83    #[test]
84    fn new_and_get_state_match_view2d() {
85        let wrapper = WasmView2d::new();
86        let core = View2d::default();
87
88        assert_vec3_close(
89            wrapper.get_state(),
90            (core.center_x, core.center_y, core.view_size),
91        );
92    }
93
94    #[test]
95    fn set_state_pan_zoom_fit_and_zoom_factor_delegate_to_view2d() {
96        let mut wrapper = WasmView2d::new();
97        let mut core = View2d::default();
98
99        wrapper.set_state(30.0, -12.5, 8.0);
100        core.set(30.0, -12.5, 8.0);
101        assert_vec3_close(
102            wrapper.get_state(),
103            (core.center_x, core.center_y, core.view_size),
104        );
105
106        wrapper.pan(5.0, -3.0, 720.0);
107        core.pan(5.0, -3.0, 720.0);
108        assert_vec3_close(
109            wrapper.get_state(),
110            (core.center_x, core.center_y, core.view_size),
111        );
112
113        wrapper.zoom_at(120.0, 320.0, 240.0, 1280.0, 720.0);
114        core.zoom_at(120.0, 320.0, 240.0, 1280.0, 720.0);
115        assert_vec3_close(
116            wrapper.get_state(),
117            (core.center_x, core.center_y, core.view_size),
118        );
119
120        wrapper.fit(1920.0, 1080.0, 800.0, 600.0);
121        core.fit(1920.0, 1080.0, 800.0, 600.0);
122        assert_vec3_close(
123            wrapper.get_state(),
124            (core.center_x, core.center_y, core.view_size),
125        );
126
127        let wrapper_zoom = wrapper.zoom_factor(64.0);
128        let core_zoom = core.zoom_factor(64.0);
129        assert!((wrapper_zoom - core_zoom).abs() < EPS);
130    }
131
132    #[test]
133    fn coordinate_conversions_return_fixed_vec_shapes_and_match_view2d() {
134        let wrapper = WasmView2d::new();
135        let core = View2d::default();
136
137        let wrapper_world = wrapper.canvas_to_world(200.0, 150.0, 800.0, 600.0);
138        let core_world = core.canvas_to_world(200.0, 150.0, 800.0, 600.0);
139        assert_vec2_close(wrapper_world, core_world);
140
141        let wrapper_canvas = wrapper.world_to_canvas(0.25, -0.5, 800.0, 600.0);
142        let core_canvas = core.world_to_canvas(0.25, -0.5, 800.0, 600.0);
143        assert_vec2_close(wrapper_canvas, core_canvas);
144    }
145}