jiao_web/
path.rs

1// Copyright (c) 2023 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
2// Use of this source is governed by Apache-2.0 License that can be found
3// in the LICENSE file.
4
5use jiao::base::{PointF, RectF};
6use jiao::kernel::PathTrait;
7use std::any::Any;
8use std::f64::consts::PI;
9use web_sys::Path2d;
10
11#[derive(Debug, Clone)]
12pub struct Path {
13    path2d: Path2d,
14}
15
16impl Default for Path {
17    fn default() -> Self {
18        Self::new()
19    }
20}
21
22impl Path {
23    /// # Panics
24    /// Got panic if failed to create path2d object.
25    #[must_use]
26    pub fn new() -> Self {
27        let path2d = Path2d::new().unwrap();
28        Self { path2d }
29    }
30
31    /// Get inner `Path2D` object.
32    #[must_use]
33    pub const fn path2d(&self) -> &Path2d {
34        &self.path2d
35    }
36}
37
38impl PathTrait for Path {
39    fn as_any(&self) -> &dyn Any {
40        self
41    }
42
43    fn clear(&mut self) {
44        self.path2d = Path2d::new().unwrap();
45    }
46
47    #[inline]
48    fn add_path(&mut self, other: &dyn PathTrait) {
49        let other_ref = other.as_any().downcast_ref::<Self>().unwrap();
50        self.path2d().add_path(other_ref.path2d());
51    }
52
53    #[inline]
54    fn close_path(&mut self) {
55        self.path2d.close_path();
56    }
57
58    #[inline]
59    fn move_to(&mut self, point: PointF) {
60        self.path2d.move_to(point.x(), point.y());
61    }
62
63    #[inline]
64    fn line_to(&mut self, point: PointF) {
65        self.path2d.line_to(point.x(), point.y());
66    }
67
68    fn add_rect(&mut self, rect: &RectF) {
69        self.path2d
70            .rect(rect.x(), rect.y(), rect.width(), rect.height());
71    }
72
73    fn add_round_rect(&mut self, rect: &RectF, radius: f64) {
74        // TODO(Shaohua):
75        //self.path2d
76        //   .round_rect(rect.x(), rect.y(), rect.width(), rect.height(), radius);
77
78        let x = rect.x();
79        let y = rect.y();
80        let width = rect.width();
81        let height = rect.height();
82
83        // TODO(Shaohua): Returns error.
84        let _ret = self.path2d.arc(
85            x + width - radius,
86            y + radius,
87            radius,
88            -90.0_f64.to_radians(),
89            0.0_f64.to_radians(),
90        );
91        let _ret = self.path2d.arc(
92            x + width - radius,
93            y + height - radius,
94            radius,
95            0.0_f64.to_radians(),
96            90.0_f64.to_radians(),
97        );
98        let _ret = self.path2d.arc(
99            x + radius,
100            y + height - radius,
101            radius,
102            90.0_f64.to_radians(),
103            180.0_f64.to_radians(),
104        );
105        let _ret = self.path2d.arc(
106            x + radius,
107            y + radius,
108            radius,
109            180.0_f64.to_radians(),
110            270.0_f64.to_radians(),
111        );
112        self.path2d.close_path();
113    }
114
115    fn add_circle(&mut self, center: PointF, radius: f64) {
116        let start_angle = 0.0;
117        let end_angle = 2.0 * PI;
118        let _ret = self
119            .path2d
120            .arc(center.x(), center.y(), radius, start_angle, end_angle);
121    }
122
123    fn add_ellipse(&mut self, rect: &RectF) {
124        let center = rect.center();
125        let radius_x = rect.width() / 2.0;
126        let radius_y = rect.height() / 2.0;
127        let rotation = 0.0;
128        let start_angle = 0.0;
129        let end_angle = 2.0 * PI;
130        let _ret = self.path2d.ellipse(
131            center.x(),
132            center.y(),
133            radius_x,
134            radius_y,
135            rotation,
136            start_angle,
137            end_angle,
138        );
139    }
140
141    fn arc(&mut self, center: PointF, radius: f64, start_angle: f64, end_angle: f64) {
142        let _ret = self
143            .path2d
144            .arc(center.x(), center.y(), radius, start_angle, end_angle);
145    }
146
147    fn arc_to(&mut self, p1: PointF, p2: PointF, radius: f64) {
148        let _ret = self.path2d.arc_to(p1.x(), p1.y(), p2.x(), p2.y(), radius);
149    }
150
151    fn ellipse(
152        &mut self,
153        center: PointF,
154        radius_x: f64,
155        radius_y: f64,
156        start_angle: f64,
157        end_angle: f64,
158    ) {
159        let rotation = 0.0;
160        let _ret = self.path2d.ellipse(
161            center.x(),
162            center.y(),
163            radius_x,
164            radius_y,
165            rotation,
166            start_angle,
167            end_angle,
168        );
169    }
170
171    fn cubic_to(&mut self, p1: PointF, p2: PointF, end_point: PointF) {
172        self.path2d
173            .bezier_curve_to(p1.x(), p1.y(), p2.x(), p2.y(), end_point.x(), end_point.y());
174    }
175
176    fn quad_to(&mut self, control_point: PointF, end_point: PointF) {
177        self.path2d.quadratic_curve_to(
178            control_point.x(),
179            control_point.y(),
180            end_point.x(),
181            end_point.y(),
182        );
183    }
184}