1use std::rc::Rc;
2
3use wasm_bindgen::prelude::*;
4
5use crate::{objects::{geometry::tipable::Tipable, plotting::function_plotter::ParametricFunctionPlot, vector_object::VectorObjectBuilder}, utils::{interpolation::{inverse_lerp, lerp}, interval::ClosedInterval, point2d::Point2D, style::{Color, Style}}};
6
7#[wasm_bindgen]
9#[derive(Clone)]
10pub struct Tick {
11 value: f32,
12 label: Option<VectorObjectBuilder>,
13 size: f32,
14 style: Style,
15 stroke_width: f32,
16}
17
18#[wasm_bindgen]
19impl Tick {
20 #[wasm_bindgen(constructor, return_description = "A new tick.")]
22 pub fn new(
23 #[wasm_bindgen(param_description = "The value of the tick.")]
24 value: f32,
25 #[wasm_bindgen(param_description = "The label of the tick.")]
26 label: Option<VectorObjectBuilder>,
27 #[wasm_bindgen(param_description = "The size of the tick.")]
28 size: Option<f32>,
29 #[wasm_bindgen(param_description = "The style of the tick.")]
30 style: Option<Style>,
31 #[wasm_bindgen(param_description = "The stroke width of the tick.")]
32 stroke_width: Option<f32>,
33 ) -> Tick {
34 Tick { value, label, size: size.unwrap_or(10.0), stroke_width: stroke_width.unwrap_or(4.0), style: style.unwrap_or(Style::from_color(Color::new(0, 0, 0, 1.0))) }
35 }
36
37 #[wasm_bindgen(getter, return_description = "The value of the tick.")]
39 pub fn value(&self) -> f32 {
40 self.value
41 }
42
43 #[wasm_bindgen(getter, return_description = "The label of the tick.")]
45 pub fn label(&self) -> Option<VectorObjectBuilder> {
46 match &self.label {
47 Some(label) => Some(label.clone()),
48 None => None,
49 }
50 }
51
52 #[wasm_bindgen(getter, return_description = "The size of the tick.")]
54 pub fn size(&self) -> f32 {
55 self.size
56 }
57
58 #[wasm_bindgen(getter, return_description = "The style of the tick.")]
60 pub fn style(&self) -> Style {
61 self.style.clone()
62 }
63
64 #[wasm_bindgen(getter, return_description = "The stroke width of the tick.")]
66 pub fn stroke_width(&self) -> f32 {
67 self.stroke_width
68 }
69}
70
71#[wasm_bindgen]
73#[derive(Clone)]
74pub struct Axis {
75 range: ClosedInterval,
76 render_start: Point2D,
77 render_end: Point2D,
78 label: Option<VectorObjectBuilder>,
79 ticks: Rc<Vec<Tick>>,
80 style: Style,
81 stroke_width: f32,
82}
83
84#[wasm_bindgen]
85impl Axis {
86 #[wasm_bindgen(constructor, return_description = "A new axis.")]
88 pub fn new(
89 #[wasm_bindgen(param_description = "The range of the axis.")]
90 range: ClosedInterval,
91 #[wasm_bindgen(param_description = "The minimum coordinates of the axis when rendered.")]
92 render_start: Point2D,
93 #[wasm_bindgen(param_description = "The maximum coordinates of the axis when rendered.")]
94 render_end: Point2D,
95 #[wasm_bindgen(param_description = "The label of the axis.")]
96 label: Option<VectorObjectBuilder>,
97 #[wasm_bindgen(param_description = "The ticks of the axis.")]
98 ticks: Option<Vec<Tick>>,
99 #[wasm_bindgen(param_description = "The style of the axis.")]
100 style: Option<Style>,
101 #[wasm_bindgen(param_description = "The stroke width of the axis.")]
102 stroke_width: Option<f32>,
103 ) -> Axis {
104 let style = style.unwrap_or(Style::from_color(Color::new(0, 0, 0, 1.0)));
105 let stroke_width = stroke_width.unwrap_or(5.0);
106 Axis { range, label, ticks: Rc::new(ticks.unwrap_or_default()), render_start, render_end, style, stroke_width }
107 }
108
109 #[wasm_bindgen(getter, return_description = "The range of the axis.")]
111 pub fn range(&self) -> ClosedInterval {
112 self.range.clone()
113 }
114
115 #[wasm_bindgen(getter, return_description = "The minimum x-coordinate of the axis when rendered.")]
117 pub fn render_start(&self) -> Point2D {
118 self.render_start
119 }
120
121 #[wasm_bindgen(getter, return_description = "The maximum x-coordinate of the axis when rendered.")]
123 pub fn render_end(&self) -> Point2D {
124 self.render_end
125 }
126
127 #[wasm_bindgen(getter, return_description = "The label of the axis.")]
129 pub fn label(&self) -> Option<VectorObjectBuilder> {
130 self.label.clone()
131 }
132
133 #[wasm_bindgen(getter, return_description = "The ticks of the axis.")]
135 pub fn ticks(&self) -> Vec<Tick> {
136 self.ticks.to_vec()
137 }
138
139 #[wasm_bindgen(getter, return_description = "The style of the axis.")]
141 pub fn style(&self) -> Style {
142 self.style.clone()
143 }
144
145 #[wasm_bindgen(getter, return_description = "The number of ticks on the axis.")]
147 pub fn num_ticks(&self) -> usize {
148 self.ticks.len()
149 }
150
151 #[wasm_bindgen(return_description = "The tick at the given number.")]
153 pub fn tick(
154 &self,
155 #[wasm_bindgen(param_description = "The number coo")]
156 num: f32
157 ) -> Option<Tick> {
158 self.ticks.iter().find(|tick| (tick.value - num).abs() < 0.0001).cloned()
159 }
160
161 #[wasm_bindgen(return_description = "The coordinates of the point in the axis.")]
163 pub fn coord_to_point(&self, num: f32) -> Point2D {
164 let t = inverse_lerp(self.range.start(), self.range.end(), num);
165 Point2D::lerp(&self.render_start, &self.render_end, t)
166 }
167
168 #[wasm_bindgen(return_description = "The value of the point in the axis.")]
170 pub fn point_to_coord(&self, point: Point2D) -> f32 {
171 let t = point.project_onto_line(&self.render_start, &self.render_end);
172 lerp(self.range.start(), self.range.end(), t)
173 }
174
175 #[wasm_bindgen(return_description = "A vector object builder with the axis.")]
177 pub fn vector_object_builder(
178 &self,
179 #[wasm_bindgen(param_description = "The direction of the label. The default is (1, 0).")]
180 label_direction: Option<Point2D>,
181 #[wasm_bindgen(param_description = "The offset of the label. The default is 20.0.")]
182 label_offset: Option<f32>,
183 #[wasm_bindgen(param_description = "The direction of the tick label. The default is (0, 1).")]
184 tick_label_direction: Option<Point2D>,
185 #[wasm_bindgen(param_description = "The offset of the tick label. The default is 10.0.")]
186 tick_label_offset: Option<f32>,
187 #[wasm_bindgen(param_description = "Whether to add the axis label. The default is true.")]
188 add_label: Option<bool>,
189 ) -> VectorObjectBuilder {
190 let mut builder = VectorObjectBuilder::default()
191 .move_point(&self.render_start)
192 .line_to(&self.render_end)
193 .set_stroke(self.style.clone(), None)
194 .set_stroke_width(self.stroke_width, None);
195 for tick in self.ticks.iter() {
196 let point = self.coord_to_point(tick.value());
197 let rotation = (self.render_end - self.render_start).direction();
198 let tick_start = (point + Point2D::new(0.0, -tick.size() / 2.0)).rotate_around(point, rotation);
199 let tick_end = (point + Point2D::new(0.0, tick.size() / 2.0)).rotate_around(point, rotation);
200 let mut child_builder = VectorObjectBuilder::default()
201 .move_point(&tick_start)
202 .line_to(&tick_end)
203 .set_stroke(tick.style.clone(), None)
204 .set_stroke_width(tick.stroke_width, None);
205 if let Some(label) = &tick.label {
206 let the_child_builder = child_builder.clone();
207 let label_direction = tick_label_direction.unwrap_or(Point2D::new(0.0, 1.0));
208 let label_offset = tick_label_offset.unwrap_or(10.0);
209 child_builder = child_builder.add_child(label.clone().next_to_other(the_child_builder, Some(label_direction), Some(label_offset), None, None));
210 }
211 builder = builder.add_child(child_builder.clone());
212 }
213 if add_label.unwrap_or(true) {
214 if let Some(label) = &self.label {
215 let the_builder = builder.clone();
216 let label_direction = label_direction.unwrap_or(Point2D::new(1.0, 0.0));
217 let label_offset = label_offset.unwrap_or(20.0);
218 builder = builder.add_child(label.clone().next_to_other(the_builder, Some(label_direction), Some(label_offset), None, None));
219 }
220 }
221 builder
222 }
223
224 #[wasm_bindgen(return_description = "A VectorObjectBuilder with the axis and tip at the end.")]
226 pub fn with_tip_at_the_end(
227 &self,
228 #[wasm_bindgen(param_description = "The shape of the tip. The shape must be pointing to the right and centered to (0, 0), this function will rotate and move it to the correct angle.")]
229 tip_shape: VectorObjectBuilder,
230 #[wasm_bindgen(param_description = "The direction of the label. The default is (1, 0).")]
231 label_direction: Option<Point2D>,
232 #[wasm_bindgen(param_description = "The offset of the label. The default is 20.0.")]
233 label_offset: Option<f32>,
234 #[wasm_bindgen(param_description = "The direction of the tick label. The default is (0, 1).")]
235 tick_label_direction: Option<Point2D>,
236 #[wasm_bindgen(param_description = "The offset of the tick label. The default is 10.0.")]
237 tick_label_offset: Option<f32>,
238 ) -> VectorObjectBuilder {
239 let mut builder = self.vector_object_builder(label_direction, label_offset, tick_label_direction, tick_label_offset, Some(false));
240 builder = builder.add_child(self.tip_at_end(tip_shape));
241 if let Some(label) = &self.label {
242 let the_builder = builder.clone();
243 let label_direction = label_direction.unwrap_or(Point2D::new(1.0, 0.0));
244 let label_offset = label_offset.unwrap_or(20.0);
245 builder = builder.add_child(label.clone().next_to_other(the_builder, Some(label_direction), Some(label_offset), None, None));
246 }
247 builder
248 }
249
250 #[wasm_bindgen(return_description = "A VectorObjectBuilder with the axis and tips at both ends.")]
252 pub fn with_tips_at_both_ends(
253 &self,
254 #[wasm_bindgen(param_description = "The shape of the tip. The shape must be pointing to the right, this function will rotate and move it to the correct angle.")]
255 tip_shape: VectorObjectBuilder,
256 #[wasm_bindgen(param_description = "The direction of the label. The default is (1, 0).")]
257 label_direction: Option<Point2D>,
258 #[wasm_bindgen(param_description = "The offset of the label. The default is 20.0.")]
259 label_offset: Option<f32>,
260 #[wasm_bindgen(param_description = "The direction of the tick label. The default is (0, 1).")]
261 tick_label_direction: Option<Point2D>,
262 #[wasm_bindgen(param_description = "The offset of the tick label. The default is 10.0.")]
263 tick_label_offset: Option<f32>,
264 ) -> VectorObjectBuilder {
265 let mut builder = self.vector_object_builder(label_direction, label_offset, tick_label_direction, tick_label_offset, Some(false));
266 builder = builder.add_child(self.tip_at_start(tip_shape.clone()));
267 builder = builder.add_child(self.tip_at_end(tip_shape));
268 if let Some(label) = &self.label {
269 let the_builder = builder.clone();
270 let label_direction = label_direction.unwrap_or(Point2D::new(1.0, 0.0));
271 let label_offset = label_offset.unwrap_or(20.0);
272 builder = builder.add_child(label.clone().next_to_other(the_builder, Some(label_direction), Some(label_offset), None, None));
273 }
274 builder
275 }
276
277 #[wasm_bindgen(js_name = clone)]
279 pub fn copy(&self) -> Axis {
280 self.clone()
281 }
282}
283
284impl Tipable for Axis {
285 fn angle_at_end(&self) -> f32 {
286 (self.render_end - self.render_start).direction()
287 }
288
289 fn angle_at_start(&self) -> f32 {
290 (self.render_start - self.render_end).direction()
291 }
292
293 fn end(&self) -> Point2D {
294 self.render_end
295 }
296
297 fn start(&self) -> Point2D {
298 self.render_start
299 }
300}
301
302#[wasm_bindgen]
304#[derive(Clone)]
305pub struct CartesianAxes {
306 x_axis: Axis,
307 y_axis: Axis,
308 coord_to_point: &'static dyn Fn(Point2D) -> Point2D
309}
310
311#[wasm_bindgen]
312impl CartesianAxes {
313 #[wasm_bindgen(constructor, return_description = "A new Cartesian axes.")]
315 pub fn new(
316 #[wasm_bindgen(param_description = "The x-range of the Cartesian axes.")]
317 x_range: ClosedInterval,
318 #[wasm_bindgen(param_description = "The y-range of the Cartesian axes.")]
319 y_range: ClosedInterval,
320 #[wasm_bindgen(param_description = "The minimum coordinates of the Cartesian axes when rendered.")]
321 render_start: Point2D,
322 #[wasm_bindgen(param_description = "The maximum coordinates of the Cartesian axes when rendered.")]
323 render_end: Point2D,
324 #[wasm_bindgen(param_description = "The style of each axis.")]
325 style: Option<Style>,
326 #[wasm_bindgen(param_description = "The stroke width of each axis.")]
327 stroke_width: Option<f32>,
328 #[wasm_bindgen(param_description = "The x-axis label.")]
329 x_label: Option<VectorObjectBuilder>,
330 #[wasm_bindgen(param_description = "The y-axis label.")]
331 y_label: Option<VectorObjectBuilder>,
332 #[wasm_bindgen(param_description = "The x-axis ticks.")]
333 x_ticks: Option<Vec<Tick>>,
334 #[wasm_bindgen(param_description = "The y-axis ticks.")]
335 y_ticks: Option<Vec<Tick>>,
336 ) -> CartesianAxes {
337 let x_ticks = match x_ticks {
338 Some(ticks) => Rc::new(ticks),
339 None => Rc::new(vec![]),
340 };
341 let y_ticks = match y_ticks {
342 Some(ticks) => Rc::new(ticks),
343 None => Rc::new(vec![]),
344 };
345 let mut x_axis = Box::new(Axis::new(x_range.clone(), render_start, render_end, x_label.clone(), Some(x_ticks.to_vec()), style.clone(), stroke_width));
346 let mut y_axis = Box::new(Axis::new(y_range.clone(), render_start, render_end, y_label.clone(), Some(y_ticks.to_vec()), style.clone(), stroke_width));
347 if y_range.start() > 0.0 {
348 x_axis = Box::new(Axis::new(
349 x_range.clone(),
350 Point2D::new(render_start.x, x_axis.coord_to_point(y_range.start()).y),
351 Point2D::new(render_end.x, x_axis.coord_to_point(y_range.start()).y),
352 x_label.clone(),
353 Some(x_ticks.to_vec()),
354 style.clone(),
355 stroke_width
356 ));
357 } else if y_range.end() < 0.0 {
358 x_axis = Box::new(Axis::new(
359 x_range.clone(),
360 Point2D::new(render_start.x, x_axis.coord_to_point(y_range.end()).y),
361 Point2D::new(render_end.x, x_axis.coord_to_point(y_range.end()).y),
362 x_label.clone(),
363 Some(x_ticks.to_vec()),
364 style.clone(),
365 stroke_width
366 ));
367 } else {
368 x_axis = Box::new(Axis::new(
369 x_range.clone(),
370 Point2D::new(render_start.x, x_axis.coord_to_point(0.0).y),
371 Point2D::new(render_end.x, x_axis.coord_to_point(0.0).y),
372 x_label.clone(),
373 Some(x_ticks.to_vec()),
374 style.clone(),
375 stroke_width
376 ));
377 }
378 if x_range.start() > 0.0 {
379 y_axis = Box::new(Axis::new(
380 y_range.clone(),
381 Point2D::new(y_axis.coord_to_point(x_range.start()).x, render_start.y),
382 Point2D::new(y_axis.coord_to_point(x_range.start()).x, render_end.y),
383 y_label.clone(),
384 Some(y_ticks.to_vec()),
385 style.clone(),
386 stroke_width
387 ));
388 } else if x_range.end() < 0.0 {
389 y_axis = Box::new(Axis::new(
390 y_range.clone(),
391 Point2D::new(y_axis.coord_to_point(x_range.end()).x, render_start.y),
392 Point2D::new(y_axis.coord_to_point(x_range.end()).x, render_end.y),
393 y_label.clone(),
394 Some(y_ticks.to_vec()),
395 style.clone(),
396 stroke_width
397 ));
398 } else {
399 y_axis = Box::new(Axis::new(
400 y_range.clone(),
401 Point2D::new(y_axis.coord_to_point(0.0).x, render_start.y),
402 Point2D::new(y_axis.coord_to_point(0.0).x, render_end.y),
403 y_label.clone(),
404 Some(y_ticks.to_vec()),
405 style.clone(),
406 stroke_width
407 ));
408 }
409 let the_x_axis = Box::leak(x_axis.clone());
410 let the_y_axis = Box::leak(y_axis.clone());
411 CartesianAxes {
412 x_axis: the_x_axis.clone(),
413 y_axis: the_y_axis.clone(),
414 coord_to_point: Box::leak(Box::new(|point: Point2D| -> Point2D {
415 Point2D::new(the_x_axis.coord_to_point(point.x).x, the_y_axis.coord_to_point(point.y).y)
416 }))
417 }
418 }
419
420 #[wasm_bindgen(getter, return_description = "The x-axis of the Cartesian axes.")]
422 pub fn x_axis(&self) -> Axis {
423 self.x_axis.clone()
424 }
425
426 #[wasm_bindgen(getter, return_description = "The y-axis of the Cartesian axes.")]
428 pub fn y_axis(&self) -> Axis {
429 self.y_axis.clone()
430 }
431
432 #[wasm_bindgen(return_description = "A vector object builder with the Cartesian axes.")]
434 pub fn vector_object_builder(
435 &self,
436 #[wasm_bindgen(param_description = "The direction of the x-label. The default is (1, 0).")]
437 x_label_direction: Option<Point2D>,
438 #[wasm_bindgen(param_description = "The offset of the x-label. The default is 20.0.")]
439 x_label_offset: Option<f32>,
440 #[wasm_bindgen(param_description = "The direction of the x-tick label. The default is (0, 1).")]
441 x_tick_label_direction: Option<Point2D>,
442 #[wasm_bindgen(param_description = "The offset of the x-tick label. The default is 10.0.")]
443 x_tick_label_offset: Option<f32>,
444 #[wasm_bindgen(param_description = "The direction of the y-label. The default is (1, 0).")]
445 y_label_direction: Option<Point2D>,
446 #[wasm_bindgen(param_description = "The offset of the y-label. The default is 20.0.")]
447 y_label_offset: Option<f32>,
448 #[wasm_bindgen(param_description = "The direction of the y-tick label. The default is (0, 1).")]
449 y_tick_label_direction: Option<Point2D>,
450 #[wasm_bindgen(param_description = "The offset of the y-tick label. The default is 10.0.")]
451 y_tick_label_offset: Option<f32>,
452 ) -> VectorObjectBuilder {
453 let mut builder = VectorObjectBuilder::default();
454 builder = builder.add_child(self.x_axis.vector_object_builder(x_label_direction, x_label_offset, x_tick_label_direction, x_tick_label_offset, None));
455 builder = builder.add_child(self.y_axis.vector_object_builder(y_label_direction, y_label_offset, y_tick_label_direction, y_tick_label_offset, None));
456 builder
457 }
458
459
460 #[wasm_bindgen(return_description = "A VectorObjectBuilder with the Cartesian axes and tip at the end of both axes.")]
462 pub fn with_tips_at_ends(
463 &self,
464 #[wasm_bindgen(param_description = "The shape of the tip. The shape must be pointing to the right, this function will rotate and move it to the correct angle.")]
465 tip_shape: VectorObjectBuilder,
466 #[wasm_bindgen(param_description = "The direction of the x-label. The default is (1, 0).")]
467 x_label_direction: Option<Point2D>,
468 #[wasm_bindgen(param_description = "The offset of the x-label. The default is 20.0.")]
469 x_label_offset: Option<f32>,
470 #[wasm_bindgen(param_description = "The direction of the x-tick label. The default is (0, 1).")]
471 x_tick_label_direction: Option<Point2D>,
472 #[wasm_bindgen(param_description = "The offset of the x-tick label. The default is 10.0.")]
473 x_tick_label_offset: Option<f32>,
474 #[wasm_bindgen(param_description = "The direction of the y-label. The default is (1, 0).")]
475 y_label_direction: Option<Point2D>,
476 #[wasm_bindgen(param_description = "The offset of the y-label. The default is 20.0.")]
477 y_label_offset: Option<f32>,
478 #[wasm_bindgen(param_description = "The direction of the y-tick label. The default is (0, 1).")]
479 y_tick_label_direction: Option<Point2D>,
480 #[wasm_bindgen(param_description = "The offset of the y-tick label. The default is 10.0.")]
481 y_tick_label_offset: Option<f32>,
482 ) -> VectorObjectBuilder {
483 let mut builder = VectorObjectBuilder::default();
484 let y_label_direction = y_label_direction.unwrap_or(Point2D::new(0.0, -1.0));
485 let y_tick_label_direction = y_tick_label_direction.unwrap_or(Point2D::new(-1.0, 0.0));
486 builder = builder.add_child(self.x_axis.with_tip_at_the_end(tip_shape.clone(), x_label_direction, x_label_offset, x_tick_label_direction, x_tick_label_offset));
487 builder = builder.add_child(self.y_axis.with_tip_at_the_end(tip_shape, Some(y_label_direction), y_label_offset, Some(y_tick_label_direction), y_tick_label_offset));
488 builder
489 }
490
491 #[wasm_bindgen(return_description = "A VectorObjectBuilder with the Cartesian axes and tips at both ends of both axes.")]
493 pub fn with_tips_at_both_ends(
494 &self,
495 #[wasm_bindgen(param_description = "The shape of the tip. The shape must be pointing to the right, this function will rotate and move it to the correct angle.")]
496 tip_shape: VectorObjectBuilder,
497 #[wasm_bindgen(param_description = "The direction of the x-label. The default is (1, 0).")]
498 x_label_direction: Option<Point2D>,
499 #[wasm_bindgen(param_description = "The offset of the x-label. The default is 20.0.")]
500 x_label_offset: Option<f32>,
501 #[wasm_bindgen(param_description = "The direction of the x-tick label. The default is (0, 1).")]
502 x_tick_label_direction: Option<Point2D>,
503 #[wasm_bindgen(param_description = "The offset of the x-tick label. The default is 10.0.")]
504 x_tick_label_offset: Option<f32>,
505 #[wasm_bindgen(param_description = "The direction of the y-label. The default is (1, 0).")]
506 y_label_direction: Option<Point2D>,
507 #[wasm_bindgen(param_description = "The offset of the y-label. The default is 20.0.")]
508 y_label_offset: Option<f32>,
509 #[wasm_bindgen(param_description = "The direction of the y-tick label. The default is (0, 1).")]
510 y_tick_label_direction: Option<Point2D>,
511 #[wasm_bindgen(param_description = "The offset of the y-tick label. The default is 10.0.")]
512 y_tick_label_offset: Option<f32>,
513 ) -> VectorObjectBuilder {
514 let mut builder = VectorObjectBuilder::default();
515 builder = builder.add_child(self.x_axis.with_tips_at_both_ends(tip_shape.clone(), x_label_direction, x_label_offset, x_tick_label_direction, x_tick_label_offset));
516 builder = builder.add_child(self.y_axis.with_tips_at_both_ends(tip_shape, y_label_direction, y_label_offset, y_tick_label_direction, y_tick_label_offset));
517 builder
518 }
519
520 #[wasm_bindgen(return_description = "The associated point of the given coordinates in the Cartesian axes.")]
522 pub fn coord_to_point(&self, p: Point2D) -> Point2D {
523 Point2D::new(self.x_axis.coord_to_point(p.x).x, self.y_axis.coord_to_point(p.y).y)
524 }
525
526 #[wasm_bindgen(return_description = "The associated coordinates of the given point in the Cartesian axes.")]
528 pub fn point_to_coord(&self, point: Point2D) -> Point2D {
529 Point2D::new(self.x_axis.point_to_coord(Point2D::new(point.x, 0.0)), self.y_axis.point_to_coord(Point2D::new(0.0, point.y)))
530 }
531
532 #[wasm_bindgen(return_description = "The ParametricFunctionPlot object with the given function.")]
534 pub fn plot_function(
535 &self,
536 #[wasm_bindgen(param_description = "The x function to plot.")]
537 expression_x: String,
538 #[wasm_bindgen(param_description = "The y function to plot.")]
539 expression_y: String,
540 #[wasm_bindgen(param_description = "The domain of the parametric function.")]
541 domain: ClosedInterval,
542 #[wasm_bindgen(param_description = "The x-range of the plot.")]
543 x_range: ClosedInterval,
544 #[wasm_bindgen(param_description = "The y-range of the plot.")]
545 y_range: ClosedInterval,
546 #[wasm_bindgen(param_description = "The discontinuities of the plot.", unchecked_param_type = "number[]")]
547 discontinuities: Option<Vec<f32>>,
548 #[wasm_bindgen(param_description = "The minimum depth of the plot.")]
549 min_depth: Option<u32>,
550 #[wasm_bindgen(param_description = "The maximum depth of the plot.")]
551 max_depth: Option<u32>,
552 #[wasm_bindgen(param_description = "The threshold of the plot.")]
553 threshold: Option<f32>,
554 ) -> Result<ParametricFunctionPlot, JsError> {
555 let mut plot = ParametricFunctionPlot::new(
556 expression_x,
557 expression_y,
558 domain,
559 x_range,
560 y_range,
561 discontinuities,
562 min_depth,
563 max_depth,
564 threshold,
565 )?;
566 plot.compose(Box::new(self.coord_to_point));
567 Ok(plot)
568 }
569
570 #[wasm_bindgen(js_name = clone)]
572 pub fn copy(&self) -> CartesianAxes {
573 self.clone()
574 }
575}