1use 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 #[must_use]
26 pub fn new() -> Self {
27 let path2d = Path2d::new().unwrap();
28 Self { path2d }
29 }
30
31 #[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 let x = rect.x();
79 let y = rect.y();
80 let width = rect.width();
81 let height = rect.height();
82
83 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}