1use std::{rc::Rc, sync::Arc};
2
3use base64::{prelude::BASE64_STANDARD, Engine};
4use usvg::{ImageHrefResolver, ImageKind};
5use wasm_bindgen::{prelude::*, throw_str};
6use crate::{objects::geometry::triangle::EquilateralTriangle, utils::{bezier::CubicBezierTuple, bounding_box::BoundingBox, console::log, font_face::FontFace, image_library::ImageLibrary, interpolation::IntegerLerp, linear_algebra::TransformationMatrix, point2d::{Path2D, Point2D}, style::{Color, ImageBitmap, Style}}};
7
8use super::geometry::rectangle::Rectangle;
9
10#[wasm_bindgen]
12#[derive(Clone, Debug)]
13pub struct VectorObject {
14 path: Path2D,
16 fill: Style,
18 fill_rule: Rc<String>,
20 stroke: Style,
22 stroke_width: f32,
24 stroke_line_cap: Rc<String>,
26 stroke_line_join: Rc<String>,
28 stroke_miter_limit: f32,
30 stroke_dash_offset: f32,
32 stroke_dash_array: Rc<Vec<f32>>,
34 children: Vec<VectorObject>,
36 name: Option<Rc<String>>,
38 transform: TransformationMatrix,
40}
41
42#[derive(Clone)]
43pub struct VectorOperationList {
44 operations: Vec<&'static dyn VectorOperation>,
45}
46
47impl VectorOperationList {
48 pub fn new() -> VectorOperationList {
49 VectorOperationList {
50 operations: Vec::new(),
51 }
52 }
53 pub fn add_operation(&mut self, operation: &'static dyn VectorOperation) {
54 self.operations.push(operation);
55 }
56 pub fn apply_and_return(&self, object: &mut VectorObject) -> VectorObject {
57 self.apply(object);
58 object.clone()
59 }
60}
61
62impl VectorOperation for VectorOperationList {
63 fn apply(&self, object: &mut VectorObject) {
64 for operation in &self.operations {
65 operation.apply(object);
66 }
67 }
68}
69
70pub trait VectorOperation {
71 fn apply(&self, object: &mut VectorObject);
72}
73
74pub struct Shift {
75 pub dx: f32,
76 pub dy: f32,
77 pub recursive: Option<bool>,
78}
79
80impl VectorOperation for Shift {
81 fn apply(&self, object: &mut VectorObject) {
82 let apply_transform = ApplyTransform {
83 matrix: TransformationMatrix::translate(self.dx, self.dy),
84 recursive: self.recursive,
85 };
86 apply_transform.apply(object);
87 }
88}
89
90pub struct MoveTo {
91 pub point: Point2D,
92 pub recursive: Option<bool>,
93}
94
95impl VectorOperation for MoveTo {
96 fn apply(&self, object: &mut VectorObject) {
97 let center = object.center();
98 if center.is_none() {
99 return;
100 }
101 let center = center.unwrap();
102 let shift = self.point - center;
103 let shift = Shift {
104 dx: shift.x,
105 dy: shift.y,
106 recursive: self.recursive,
107 };
108 shift.apply(object);
109 }
110}
111
112pub struct Scale {
113 pub factor_x: f32,
114 pub factor_y: f32,
115 pub about_point: Option<Point2D>,
116 pub recursive: Option<bool>,
117}
118
119impl VectorOperation for Scale {
120 fn apply(&self, object: &mut VectorObject) {
121 let about_point = if let Some(point) = self.about_point {
122 point
123 } else {
124 object.bounding_box(self.recursive).unwrap().center()
125 };
126 let shift = Shift {
127 dx: -about_point.x,
128 dy: -about_point.y,
129 recursive: self.recursive,
130 };
131 shift.apply(object);
132 let apply_transform = ApplyTransform {
133 matrix: TransformationMatrix::scale(self.factor_x, self.factor_y),
134 recursive: self.recursive,
135 };
136 apply_transform.apply(object);
137 let shift = Shift {
138 dx: about_point.x,
139 dy: about_point.y,
140 recursive: self.recursive,
141 };
142 shift.apply(object);
143 }
144}
145
146pub struct ScaleToWidth {
147 pub width: f32,
148 pub stretch: Option<bool>,
149 pub about_point: Option<Point2D>,
150 pub recursive: Option<bool>,
151}
152
153impl VectorOperation for ScaleToWidth {
154 fn apply(&self, object: &mut VectorObject) {
155 let bounding_box = object.bounding_box(self.recursive);
156 if bounding_box.is_none() {
157 return;
158 }
159 let bounding_box = bounding_box.unwrap();
160 let width = bounding_box.width();
161 if width == 0.0 {
162 return;
163 }
164 let factor_x = self.width / width;
165 let factor_y = if self.stretch.unwrap_or(false) {
166 1.0
167 } else {
168 factor_x
169 };
170 let scale = Scale {
171 factor_x: factor_x,
172 factor_y: factor_y,
173 about_point: self.about_point,
174 recursive: self.recursive,
175 };
176 scale.apply(object);
177 }
178}
179
180pub struct ScaleToHeight {
181 pub height: f32,
182 pub stretch: Option<bool>,
183 pub about_point: Option<Point2D>,
184 pub recursive: Option<bool>,
185}
186
187impl VectorOperation for ScaleToHeight {
188 fn apply(&self, object: &mut VectorObject) {
189 let bounding_box = object.bounding_box(self.recursive);
190 if bounding_box.is_none() {
191 return;
192 }
193 let bounding_box = bounding_box.unwrap();
194 let height = bounding_box.height();
195 if height == 0.0 {
196 return;
197 }
198 let factor_x = if self.stretch.unwrap_or(false) {
199 1.0
200 } else {
201 self.height / height
202 };
203 let factor_y = self.height / height;
204 let scale = Scale {
205 factor_x: factor_x,
206 factor_y: factor_y,
207 about_point: self.about_point,
208 recursive: self.recursive,
209 };
210 scale.apply(object);
211 }
212}
213
214pub struct Rotate {
215 pub angle: f32,
216 pub from_point: Option<Point2D>,
217 pub recursive: Option<bool>,
218}
219
220impl VectorOperation for Rotate {
221 fn apply(&self, object: &mut VectorObject) {
222 let bounding_box = object.bounding_box(self.recursive);
223 if bounding_box.is_none() {
224 return;
225 }
226 let bounding_box = bounding_box.unwrap();
227 let center = bounding_box.center();
228 let from_point = if let Some(point) = self.from_point {
229 point
230 } else {
231 center
232 };
233 let shift = Shift {
234 dx: -from_point.x,
235 dy: -from_point.y,
236 recursive: self.recursive,
237 };
238 shift.apply(object);
239 let rotate = TransformationMatrix::rotate(self.angle);
240 let apply_transform = ApplyTransform {
241 matrix: rotate,
242 recursive: self.recursive,
243 };
244 apply_transform.apply(object);
245 let shift = Shift {
246 dx: from_point.x,
247 dy: from_point.y,
248 recursive: self.recursive,
249 };
250 shift.apply(object);
251 }
252}
253
254pub struct SetTransform {
255 pub matrix: TransformationMatrix,
256 pub recursive: Option<bool>,
257}
258
259impl VectorOperation for SetTransform {
260 fn apply(&self, object: &mut VectorObject) {
261 object.transform = self.matrix.clone();
262 if self.recursive.unwrap_or(true) {
263 for child in &mut object.children {
264 let transform = SetTransform {
265 matrix: self.matrix.clone(),
266 recursive: Some(true),
267 };
268 transform.apply(child);
269 }
270 }
271 }
272}
273
274pub struct AddChildren {
275 pub children: Vec<VectorObjectBuilder>,
276}
277
278impl VectorOperation for AddChildren {
279 fn apply(&self, object: &mut VectorObject) {
280 for child in &self.children {
281 let child = child.clone().build();
282 object.children.push(child);
283 }
284 }
285}
286
287pub struct RemoveChildByIndex {
288 pub index: usize,
289}
290
291impl VectorOperation for RemoveChildByIndex {
292 fn apply(&self, object: &mut VectorObject) {
293 object.children.remove(self.index);
294 }
295}
296
297pub struct RemoveChildByName {
298 pub name: Rc<String>,
299}
300
301impl VectorOperation for RemoveChildByName {
302 fn apply(&self, object: &mut VectorObject) {
303 object.children.retain(|child| child.name != Some(Rc::clone(&self.name)));
304 }
305}
306
307pub struct MatchStyleProperties {
308 pub vector_object_builder: VectorObjectBuilder,
309}
310
311impl VectorOperation for MatchStyleProperties {
312 fn apply(&self, object: &mut VectorObject) {
313 let vector_object = self.vector_object_builder.clone().build();
314 object.fill = vector_object.fill;
315 object.fill_rule = vector_object.fill_rule;
316 object.stroke = vector_object.stroke;
317 object.stroke_width = vector_object.stroke_width;
318 object.stroke_line_cap = vector_object.stroke_line_cap;
319 object.stroke_line_join = vector_object.stroke_line_join;
320 object.stroke_miter_limit = vector_object.stroke_miter_limit;
321 object.stroke_dash_offset = vector_object.stroke_dash_offset;
322 object.stroke_dash_array = vector_object.stroke_dash_array;
323 }
324}
325
326pub struct BecomePartial {
327 pub start: f32,
328 pub end: f32,
329 pub samples: Option<usize>,
330 pub extra_length: Option<f32>,
331 pub recursive: Option<bool>,
332}
333
334impl VectorOperation for BecomePartial {
335 fn apply(&self, object: &mut VectorObject) {
336 if self.start <= 0.0 && self.end >= 1.0 {
337 return;
338 }
339 if self.recursive.unwrap_or(true) {
340 for child in &mut object.children {
341 let become_partial = BecomePartial {
342 start: self.start,
343 end: self.end,
344 samples: self.samples,
345 extra_length: self.extra_length,
346 recursive: Some(true),
347 };
348 become_partial.apply(child);
349 }
350 }
351 let subpaths = object.subpaths();
352 let mut max_length = None;
353 for subpath in subpaths {
354 let length = subpath.length(self.samples, self.extra_length);
355 if max_length.is_none() || length > max_length.unwrap() {
356 max_length = Some(length);
357 }
358 }
359 if max_length.is_none() {
360 return;
361 }
362 let max_length = max_length.unwrap();
363 object.stroke_dash_array = Rc::new(vec![max_length * (self.end - self.start), max_length]);
364 object.stroke_dash_offset = -max_length * self.start;
365 }
366}
367
368pub struct PointwiseBecomePartial {
369 pub start: f32,
370 pub end: f32,
371 pub recursive: Option<bool>,
372}
373
374impl VectorOperation for PointwiseBecomePartial {
375 fn apply(&self, object: &mut VectorObject) {
376 if self.recursive.unwrap_or(true) {
377 for child in &mut object.children {
378 let pointwise_become_partial = PointwiseBecomePartial {
379 start: self.start,
380 end: self.end,
381 recursive: Some(true),
382 };
383 pointwise_become_partial.apply(child);
384 }
385 }
386 if self.start <= 0.0 && self.end >= 1.0 {
387 return;
388 }
389 if self.start == self.end {
390 object.path = Path2D::default();
391 return;
392 }
393 let num_curves = object.num_curves();
394 if num_curves == 0 {
395 return;
396 }
397 let lower = IntegerLerp::new(0.0, num_curves as f32, self.start);
398 let upper = IntegerLerp::new(0.0, num_curves as f32, self.end);
399 let lower_index = lower.index();
400 let lower_remainder = lower.remainder();
401 let upper_index = upper.index();
402 let upper_remainder = upper.remainder();
403 if lower_index == upper_index {
404 let start = lower_remainder;
405 let end = upper_remainder;
406 let set_actual_path = SetActualPath {
407 path: object.actual_path().slice(
408 4 * lower_index as usize,
409 (4 * lower_index + 4) as usize,
410 ).partial_bezier_path(start, end),
411 };
412 set_actual_path.apply(object);
413 } else {
414 let mut actual_path = Path2D::fill(Point2D::default(), 4 * (upper_index - lower_index + 1) as usize);
415 actual_path.set_slice(0, 4, object.actual_path().slice(
416 4 * lower_index as usize,
417 (4 * lower_index + 4) as usize,
418 ).partial_bezier_path(lower_remainder, 1.0));
419 actual_path.set_slice(4, actual_path.len() - 4, object.actual_path().slice(
420 (4 * lower_index + 4) as usize,
421 4 * upper_index as usize,
422 ));
423 actual_path.set_slice(actual_path.len() - 4, actual_path.len(), object.actual_path().slice(
424 4 * upper_index as usize,
425 (4 * upper_index + 4) as usize,
426 ).partial_bezier_path(0.0, upper_remainder));
427 let set_actual_path = SetActualPath {
428 path: actual_path,
429 };
430 set_actual_path.apply(object);
431 }
432 }
433}
434
435pub struct MovePoint {
436 pub point: Point2D,
437}
438
439impl VectorOperation for MovePoint {
440 fn apply(&self, object: &mut VectorObject) {
441 if object.num_points() % 4 == 0 {
442 object.path.push(self.point);
443 }
444 }
445}
446
447pub struct LineTo {
448 pub point: Point2D,
449}
450
451impl VectorOperation for LineTo {
452 fn apply(&self, object: &mut VectorObject) {
453 let last_point = object.path[object.path.len() - 1];
454 object.path.push_bezier(CubicBezierTuple::new(last_point, last_point, self.point, self.point));
455 }
456}
457
458pub struct QuadraticCurveTo {
459 pub p1: Point2D,
460 pub p2: Point2D,
461}
462
463impl VectorOperation for QuadraticCurveTo {
464 fn apply(&self, object: &mut VectorObject) {
465 let last_point = object.path[object.path.len() - 1];
466 object.path.push_bezier(CubicBezierTuple::from_quadratic(last_point, self.p1, self.p2));
467 }
468}
469
470pub struct BezierCurveTo {
471 pub p1: Point2D,
472 pub p2: Point2D,
473 pub p3: Point2D,
474}
475
476impl VectorOperation for BezierCurveTo {
477 fn apply(&self, object: &mut VectorObject) {
478 let last_point = object.path[object.path.len() - 1];
479 object.path.push_bezier(CubicBezierTuple::new(last_point, self.p1, self.p2, self.p3));
480 }
481}
482
483pub struct Close {}
484
485impl VectorOperation for Close {
486 fn apply(&self, object: &mut VectorObject) {
487 if object.is_closed() {
488 return;
489 }
490 let line_to = LineTo {
491 point: object.path[0],
492 };
493 line_to.apply(object);
494 }
495}
496
497pub struct FadeFill {
498 pub factor: f32,
499 pub recursive: Option<bool>,
500}
501
502impl VectorOperation for FadeFill {
503 fn apply(&self, object: &mut VectorObject) {
504 object.fill = object.fill.fade(self.factor);
505 if self.recursive.unwrap_or(true) {
506 for child in &mut object.children {
507 let fade = FadeFill {
508 factor: self.factor,
509 recursive: Some(true),
510 };
511 fade.apply(child);
512 }
513 }
514 }
515}
516
517pub struct FadeStroke {
518 pub factor: f32,
519 pub recursive: Option<bool>,
520}
521
522impl VectorOperation for FadeStroke {
523 fn apply(&self, object: &mut VectorObject) {
524 object.stroke = object.stroke.fade(self.factor);
525 if self.recursive.unwrap_or(true) {
526 for child in &mut object.children {
527 let fade = FadeStroke {
528 factor: self.factor,
529 recursive: Some(true),
530 };
531 fade.apply(child);
532 }
533 }
534 }
535}
536
537pub struct SetPath {
538 pub path: Path2D,
539}
540
541impl VectorOperation for SetPath {
542 fn apply(&self, object: &mut VectorObject) {
543 object.path = self.path.clone();
544 }
545}
546
547pub struct SetActualPath {
548 pub path: Path2D,
549}
550
551impl VectorOperation for SetActualPath {
552 fn apply(&self, object: &mut VectorObject) {
553 object.path = self.path.transform(&object.transform.inverse());
556 }
557}
558
559pub struct SetFill {
560 pub fill: Style,
561 pub recursive: Option<bool>,
562}
563
564impl VectorOperation for SetFill {
565 fn apply(&self, object: &mut VectorObject) {
566 object.fill = self.fill.clone();
567 if self.recursive.unwrap_or(true) {
568 for child in &mut object.children {
569 let set_fill = SetFill {
570 fill: self.fill.clone(),
571 recursive: Some(true),
572 };
573 set_fill.apply(child);
574 }
575 }
576 }
577}
578
579pub struct SetFillRule {
580 pub fill_rule: Rc<String>,
581 pub recursive: Option<bool>,
582}
583
584impl VectorOperation for SetFillRule {
585 fn apply(&self, object: &mut VectorObject) {
586 object.fill_rule = Rc::clone(&self.fill_rule);
587 if self.recursive.unwrap_or(true) {
588 for child in &mut object.children {
589 let set_fill_rule = SetFillRule {
590 fill_rule: Rc::clone(&self.fill_rule),
591 recursive: Some(true),
592 };
593 set_fill_rule.apply(child);
594 }
595 }
596 }
597}
598
599pub struct SetStroke {
600 pub stroke: Style,
601 pub recursive: Option<bool>,
602}
603
604impl VectorOperation for SetStroke {
605 fn apply(&self, object: &mut VectorObject) {
606 object.stroke = self.stroke.clone();
607 if self.recursive.unwrap_or(true) {
608 for child in &mut object.children {
609 let set_stroke = SetStroke {
610 stroke: self.stroke.clone(),
611 recursive: Some(true),
612 };
613 set_stroke.apply(child);
614 }
615 }
616 }
617}
618
619pub struct SetStrokeWidth {
620 pub stroke_width: f32,
621 pub recursive: Option<bool>,
622}
623
624impl VectorOperation for SetStrokeWidth {
625 fn apply(&self, object: &mut VectorObject) {
626 object.stroke_width = self.stroke_width;
627 if self.recursive.unwrap_or(true) {
628 for child in &mut object.children {
629 let set_stroke_width = SetStrokeWidth {
630 stroke_width: self.stroke_width,
631 recursive: Some(true),
632 };
633 set_stroke_width.apply(child);
634 }
635 }
636 }
637}
638
639pub struct SetStrokeLineCap {
640 pub stroke_line_cap: Rc<String>,
641 pub recursive: Option<bool>,
642}
643
644impl VectorOperation for SetStrokeLineCap {
645 fn apply(&self, object: &mut VectorObject) {
646 object.stroke_line_cap = Rc::clone(&self.stroke_line_cap);
647 if self.recursive.unwrap_or(true) {
648 for child in &mut object.children {
649 let set_stroke_line_cap = SetStrokeLineCap {
650 stroke_line_cap: self.stroke_line_cap.clone(),
651 recursive: Some(true),
652 };
653 set_stroke_line_cap.apply(child);
654 }
655 }
656 }
657}
658
659pub struct SetStrokeLineJoin {
660 pub stroke_line_join: Rc<String>,
661 pub recursive: Option<bool>,
662}
663
664impl VectorOperation for SetStrokeLineJoin {
665 fn apply(&self, object: &mut VectorObject) {
666 object.stroke_line_join = Rc::clone(&self.stroke_line_join);
667 if self.recursive.unwrap_or(true) {
668 for child in &mut object.children {
669 let set_stroke_line_join = SetStrokeLineJoin {
670 stroke_line_join: self.stroke_line_join.clone(),
671 recursive: Some(true),
672 };
673 set_stroke_line_join.apply(child);
674 }
675 }
676 }
677}
678
679pub struct SetStrokeMiterLimit {
680 pub stroke_miter_limit: f32,
681 pub recursive: Option<bool>,
682}
683
684impl VectorOperation for SetStrokeMiterLimit {
685 fn apply(&self, object: &mut VectorObject) {
686 object.stroke_miter_limit = self.stroke_miter_limit;
687 if self.recursive.unwrap_or(true) {
688 for child in &mut object.children {
689 let set_stroke_miter_limit = SetStrokeMiterLimit {
690 stroke_miter_limit: self.stroke_miter_limit,
691 recursive: Some(true),
692 };
693 set_stroke_miter_limit.apply(child);
694 }
695 }
696 }
697}
698
699pub struct SetStrokeDashOffset {
700 pub stroke_dash_offset: f32,
701 pub recursive: Option<bool>,
702}
703
704impl VectorOperation for SetStrokeDashOffset {
705 fn apply(&self, object: &mut VectorObject) {
706 object.stroke_dash_offset = self.stroke_dash_offset;
707 if self.recursive.unwrap_or(true) {
708 for child in &mut object.children {
709 let set_stroke_dash_offset = SetStrokeDashOffset {
710 stroke_dash_offset: self.stroke_dash_offset,
711 recursive: Some(true),
712 };
713 set_stroke_dash_offset.apply(child);
714 }
715 }
716 }
717}
718
719pub struct SetStrokeDashArray {
720 pub stroke_dash_array: Rc<Vec<f32>>,
721 pub recursive: Option<bool>,
722}
723
724impl VectorOperation for SetStrokeDashArray {
725 fn apply(&self, object: &mut VectorObject) {
726 object.stroke_dash_array = Rc::clone(&self.stroke_dash_array);
727 if self.recursive.unwrap_or(true) {
728 for child in &mut object.children {
729 let set_stroke_dash_array = SetStrokeDashArray {
730 stroke_dash_array: self.stroke_dash_array.clone(),
731 recursive: Some(true),
732 };
733 set_stroke_dash_array.apply(child);
734 }
735 }
736 }
737}
738
739pub struct SetChildren {
740 pub children: Vec<VectorObjectBuilder>,
741}
742
743impl VectorOperation for SetChildren {
744 fn apply(&self, object: &mut VectorObject) {
745 object.children = self.children.iter().map(|child| child.clone().build()).collect();
746 }
747}
748
749pub struct SetName {
750 pub name: Option<Rc<String>>,
751}
752
753impl VectorOperation for SetName {
754 fn apply(&self, object: &mut VectorObject) {
755 if let Some(name) = &self.name {
756 object.name = Some(Rc::clone(name));
757 } else {
758 object.name = None;
759 }
760 }
761}
762
763pub struct ActualPathAsPath {
764 pub untransform: Option<bool>,
765 pub recursive: Option<bool>,
766}
767
768impl VectorOperation for ActualPathAsPath {
769 fn apply(&self, object: &mut VectorObject) {
770 object.path = object.actual_path();
771 if self.untransform.unwrap_or(true) {
772 object.transform = TransformationMatrix::identity();
773 }
774 if self.recursive.unwrap_or(true) {
775 for child in &mut object.children {
776 let actual_path_as_path = ActualPathAsPath {
777 untransform: self.untransform,
778 recursive: Some(true),
779 };
780 actual_path_as_path.apply(child);
781 }
782 }
783 }
784}
785
786pub struct AddChild {
787 pub child: VectorObjectBuilder,
788}
789
790impl VectorOperation for AddChild {
791 fn apply(&self, object: &mut VectorObject) {
792 let child = self.child.clone().build();
793 object.children.push(child);
794 }
795}
796
797pub struct InsertChild {
798 pub index: usize,
799 pub child: VectorObjectBuilder,
800}
801
802impl VectorOperation for InsertChild {
803 fn apply(&self, object: &mut VectorObject) {
804 object.children.insert(self.index, self.child.clone().build());
805 }
806}
807
808pub struct InsertChildren {
809 pub index: usize,
810 pub children: Vec<VectorObjectBuilder>,
811}
812
813impl VectorOperation for InsertChildren {
814 fn apply(&self, object: &mut VectorObject) {
815 for (i, child) in self.children.iter().enumerate() {
816 object.children.insert(self.index + i, child.clone().build());
817 }
818 }
819}
820
821pub struct RemoveChildrenAtIndices {
822 pub indices: Vec<usize>,
823}
824
825impl VectorOperation for RemoveChildrenAtIndices {
826 fn apply(&self, object: &mut VectorObject) {
827 let mut new_children = Vec::new();
828 for (i, child) in object.children.iter().enumerate() {
829 if !self.indices.contains(&i) {
830 new_children.push(child.clone());
831 }
832 }
833 object.children = new_children;
834 }
835}
836
837pub struct RemoveChildrenByNames {
838 pub names: Vec<String>,
839}
840
841impl VectorOperation for RemoveChildrenByNames {
842 fn apply(&self, object: &mut VectorObject) {
843 object.children.retain(|child| {
844 if let Some(name) = &child.name {
845 !self.names.contains(&name)
846 } else {
847 true
848 }
849 });
850 }
851}
852
853pub struct SetSliceChildren {
854 pub start: usize,
855 pub end: usize,
856 pub children: Vec<VectorObjectBuilder>,
857}
858
859pub struct SetChildrenWithNames {
860 pub names: Vec<String>,
861 pub children: Vec<VectorObjectBuilder>,
862}
863
864impl VectorOperation for SetChildrenWithNames {
865 fn apply(&self, object: &mut VectorObject) {
866 let children = self.children.clone().iter().map(|child| child.clone().build()).collect::<Vec<VectorObject>>();
867 for child in children.iter() {
868 if let Some(name) = &child.name {
869 if self.names.contains(&name) {
870 object.children.push(child.clone());
871 }
872 }
873 }
874 }
875}
876
877impl VectorOperation for SetSliceChildren {
878 fn apply(&self, object: &mut VectorObject) {
879 object.children.splice(self.start..self.end, self.children.iter().map(|child| child.clone().build()));
880 }
881}
882
883pub struct NextToPoint {
884 pub point: Point2D,
885 pub direction: Option<Point2D>,
886 pub buff: Option<f32>,
887 pub aligned_edge: Option<Point2D>,
888 pub recursive: Option<bool>,
889}
890
891impl VectorOperation for NextToPoint {
892 fn apply(&self, object: &mut VectorObject) {
893 let bounding_box = object.bounding_box(self.recursive);
894 if bounding_box.is_none() {
895 return;
896 }
897 let direction = if let Some(direction) = self.direction {
898 direction
899 } else {
900 Point2D::new(1.0, 0.0)
901 };
902 let buff = self.buff.unwrap_or(0.0);
903 let aligned_edge = if let Some(aligned_edge) = self.aligned_edge {
904 aligned_edge
905 } else {
906 Point2D::new(0.0, 0.0)
907 };
908 let key2 = aligned_edge - direction;
909 let key2_x = key2.x;
910 let key2_y = key2.y;
911 let point_to_align = object.get_critical_point(key2_x, key2_y, self.recursive).unwrap();
912 let shift = self.point - point_to_align + buff * direction;
913 let shift = Shift {
914 dx: shift.x,
915 dy: shift.y,
916 recursive: self.recursive,
917 };
918 shift.apply(object);
919 }
920}
921
922pub struct NextToOther {
923 pub other: VectorObjectBuilder,
924 pub direction: Option<Point2D>,
925 pub buff: Option<f32>,
926 pub aligned_edge: Option<Point2D>,
927 pub recursive: Option<bool>,
928}
929
930impl VectorOperation for NextToOther {
931 fn apply(&self, object: &mut VectorObject) {
932 let bounding_box = object.bounding_box(self.recursive);
933 if bounding_box.is_none() {
934 return;
935 }
936 let other = self.other.clone().build();
937 let other_bounding_box = other.bounding_box(self.recursive);
938 if other_bounding_box.is_none() {
939 return;
940 }
941 let direction = if let Some(direction) = self.direction {
942 direction
943 } else {
944 Point2D::new(1.0, 0.0)
945 };
946 let buff = self.buff.unwrap_or(0.0);
947 let aligned_edge = if let Some(aligned_edge) = self.aligned_edge {
948 aligned_edge
949 } else {
950 Point2D::new(0.0, 0.0)
951 };
952 let key1 = aligned_edge + direction;
953 let key1_x = key1.x;
954 let key1_y = key1.y;
955 let target_point = other.get_critical_point(key1_x, key1_y, self.recursive).unwrap();
956 let next_to_point = NextToPoint {
957 point: target_point,
958 direction: Some(direction),
959 buff: Some(buff),
960 aligned_edge: Some(aligned_edge),
961 recursive: self.recursive,
962 };
963 next_to_point.apply(object);
964 }
965}
966
967pub struct ArrangeChildren {
968 pub direction: Option<Point2D>,
969 pub buff: Option<f32>,
970 pub aligned_edge: Option<Point2D>,
971 pub center: Option<Point2D>,
972 pub recursive: Option<bool>,
973}
974
975impl VectorOperation for ArrangeChildren {
976 fn apply(&self, object: &mut VectorObject) {
977 let buff = self.buff.unwrap_or(0.0);
978 let aligned_edge = if let Some(aligned_edge) = self.aligned_edge {
979 aligned_edge
980 } else {
981 Point2D::new(0.0, 0.0)
982 };
983 let first_child = object.children[0].clone();
984 for i in 1..object.children.len() {
985 object.children[i].apply_operation(&NextToOther {
986 other: VectorObjectBuilder::new(&first_child),
987 direction: self.direction,
988 buff: Some(buff),
989 aligned_edge: Some(aligned_edge),
990 recursive: self.recursive,
991 });
992 }
993 if let Some(center) = self.center {
994 let move_to = MoveTo {
995 point: center,
996 recursive: self.recursive,
997 };
998 move_to.apply(object);
999 }
1000 }
1001}
1002
1003pub struct ReversePath {}
1004
1005impl VectorOperation for ReversePath {
1006 fn apply(&self, object: &mut VectorObject) {
1007 object.path.reverse();
1008 }
1009}
1010
1011pub struct ApplyTransform {
1012 pub matrix: TransformationMatrix,
1013 pub recursive: Option<bool>,
1014}
1015
1016impl VectorOperation for ApplyTransform {
1017 fn apply(&self, object: &mut VectorObject) {
1018 object.transform.apply(&self.matrix);
1019 if self.recursive.unwrap_or(true) {
1020 for child in &mut object.children {
1021 let apply_transform = ApplyTransform {
1022 matrix: self.matrix.clone(),
1023 recursive: Some(true),
1024 };
1025 apply_transform.apply(child);
1026 }
1027 }
1028 }
1029}
1030
1031pub struct LerpFill {
1032 pub fill: Style,
1033 pub t: f32,
1034 pub x: Option<f32>,
1035 pub y: Option<f32>,
1036 pub width: Option<f32>,
1037 pub height: Option<f32>,
1038 pub data_width: Option<usize>,
1039 pub data_height: Option<usize>,
1040 pub recursive: Option<bool>,
1041}
1042
1043impl VectorOperation for LerpFill {
1044 fn apply(&self, object: &mut VectorObject) {
1045 let fill = Style::lerp(&object.fill, &self.fill, self.t, self.x, self.y, self.width, self.height, self.data_width, self.data_height);
1046 if fill.is_err() {
1047 throw_str(&fill.unwrap_err());
1048 }
1049 object.fill = fill.unwrap();
1050 if self.recursive.unwrap_or(true) {
1051 for child in &mut object.children {
1052 let lerp_fill = LerpFill {
1053 fill: self.fill.clone(),
1054 t: self.t,
1055 x: self.x,
1056 y: self.y,
1057 width: self.width,
1058 height: self.height,
1059 data_width: self.data_width,
1060 data_height: self.data_height,
1061 recursive: Some(true),
1062 };
1063 lerp_fill.apply(child);
1064 }
1065 }
1066 }
1067}
1068
1069pub struct LerpStroke {
1070 pub stroke: Style,
1071 pub t: f32,
1072 pub x: Option<f32>,
1073 pub y: Option<f32>,
1074 pub width: Option<f32>,
1075 pub height: Option<f32>,
1076 pub data_width: Option<usize>,
1077 pub data_height: Option<usize>,
1078 pub recursive: Option<bool>,
1079}
1080
1081impl VectorOperation for LerpStroke {
1082 fn apply(&self, object: &mut VectorObject) {
1083 let stroke = Style::lerp(&object.stroke, &self.stroke, self.t, self.x, self.y, self.width, self.height, self.data_width, self.data_height);
1084 if stroke.is_err() {
1085 throw_str(&stroke.unwrap_err());
1086 }
1087 object.stroke = stroke.unwrap();
1088 if self.recursive.unwrap_or(true) {
1089 for child in &mut object.children {
1090 let lerp_stroke = LerpStroke {
1091 stroke: self.stroke.clone(),
1092 t: self.t,
1093 x: self.x,
1094 y: self.y,
1095 width: self.width,
1096 height: self.height,
1097 data_width: self.data_width,
1098 data_height: self.data_height,
1099 recursive: Some(true),
1100 };
1101 lerp_stroke.apply(child);
1102 }
1103 }
1104 }
1105}
1106
1107impl Default for VectorObject {
1108 fn default() -> Self {
1109 VectorObject {
1110 path: Path2D::default(),
1111 fill: Style::default(),
1112 fill_rule: Rc::new("nonzero".to_string()),
1113 stroke: Style::default(),
1114 stroke_width: 1.0,
1115 stroke_line_cap: Rc::new("butt".to_string()),
1116 stroke_line_join: Rc::new("miter".to_string()),
1117 stroke_miter_limit: 4.0,
1118 stroke_dash_offset: 0.0,
1119 stroke_dash_array: Rc::new(Vec::new()),
1120 children: Vec::new(),
1121 name: None,
1122 transform: TransformationMatrix::identity(),
1123 }
1124 }
1125}
1126
1127#[wasm_bindgen]
1129#[derive(Clone)]
1130pub struct VectorObjectBuilder {
1131 object: Rc<VectorObject>,
1133 ops: VectorOperationList,
1135}
1136
1137impl Default for VectorObjectBuilder {
1138 fn default() -> Self {
1139 VectorObjectBuilder {
1140 object: Rc::new(VectorObject::default()),
1141 ops: VectorOperationList::new(),
1142 }
1143 }
1144}
1145
1146#[wasm_bindgen]
1147impl VectorObjectBuilder {
1148 #[wasm_bindgen(constructor, return_description = "A new vector object builder.")]
1150 pub fn new(
1151 #[wasm_bindgen(param_description = "The vector object to start building on.")]
1152 vector_object: &VectorObject
1153 ) -> VectorObjectBuilder {
1154 VectorObjectBuilder {
1155 object: Rc::new(vector_object.clone()),
1156 ops: VectorOperationList::new(),
1157 }
1158 }
1159
1160 #[wasm_bindgen(return_description = "The default tip shape pointing to the right and centered at the origin.")]
1162 pub fn default_tip_shape(
1163 #[wasm_bindgen(param_description = "The length of the tip shape.")]
1164 tip_length: f64,
1165 ) -> VectorObjectBuilder {
1166 EquilateralTriangle::new(
1167 Point2D::new(0.0, 0.0),
1168 tip_length as f32,
1169 Some(-std::f32::consts::FRAC_PI_2),
1170 ).vector_object_builder().set_fill(Style::from_color(Color::new(0, 0, 0, 1.0)), None)
1171 }
1172
1173 #[wasm_bindgen(return_description = "A new vector object builder.")]
1175 pub fn from_svg(
1176 #[wasm_bindgen(param_description = "The SVG string to create the vector object builder from.")]
1177 svg: String,
1178 #[wasm_bindgen(param_description = "Data from font faces to use for text rendering.")]
1179 font_faces: Option<Vec<FontFace>>,
1180 #[wasm_bindgen(param_description = "Image library to use for image rendering.")]
1181 image_library: Option<ImageLibrary>,
1182 ) -> VectorObjectBuilder {
1183 let mut vector_object_builder = VectorObjectBuilder::default();
1184 let mut options = usvg::Options::default();
1185 let mut fontdatabase = options.fontdb.clone();
1186 for font_face in font_faces.unwrap_or_default() {
1187 Arc::make_mut(&mut fontdatabase).load_font_data(font_face.data());
1188 }
1189 let image_library = Box::new(image_library.unwrap_or(ImageLibrary::new()));
1190 let image_library = Box::leak(image_library);
1191 options.image_href_resolver = ImageHrefResolver {
1192 resolve_data: Box::new(|mime, data, _opts| {
1193 match mime {
1195 "image/png" => {
1196 Some(ImageKind::PNG(data))
1197 }
1198 "image/jpeg" | "image/jpg" => {
1199 Some(ImageKind::JPEG(data))
1200 }
1201 "image/gif" => {
1202 Some(ImageKind::GIF(data))
1203 }
1204 "image/webp" => {
1205 Some(ImageKind::WEBP(data))
1206 }
1207 "image/svg+xml" => {
1208 let data = image_library.get(&format!("data:image/png;base64,{}", BASE64_STANDARD.encode(data.to_vec())));
1209 if data.is_none() {
1210 return None;
1211 }
1212 Some(ImageKind::PNG(Arc::new(data.unwrap().data())))
1213 }
1214 _ => {
1215 None
1216 }
1217 }
1218 }),
1219 resolve_string: Box::new(|string, _opts| {
1220 let data = image_library.get(&string);
1221 if data.is_none() {
1222 return None;
1223 }
1224 Some(ImageKind::PNG(Arc::new(data.unwrap().data())))
1225 }),
1226 };
1227 options.fontdb = fontdatabase;
1228 let tree = usvg::Tree::from_str(&svg, &options);
1229 if tree.is_err() {
1230 log(&format!("Error parsing SVG: {}", tree.err().unwrap()));
1231 return vector_object_builder;
1232 }
1233 let tree = tree.unwrap();
1234 if !tree.root().has_children() {
1235 log("The SVG path is empty. No operations were applied.");
1236 return vector_object_builder;
1237 }
1238 let node = tree.root().children();
1239 for child in node {
1240 vector_object_builder = vector_object_builder.add_child(VectorObjectBuilder::from_node(&child));
1241 }
1242 vector_object_builder
1243 }
1244 #[wasm_bindgen(js_name = clone, return_description = "A clone of the vector object builder.")]
1246 pub fn clone_js(&self) -> VectorObjectBuilder {
1247 self.clone()
1248 }
1249 #[wasm_bindgen(return_description = "A new vector object builder representing an empty vector object.")]
1251 pub fn default_vector_object_builder() -> VectorObjectBuilder {
1252 VectorObjectBuilder::default()
1253 }
1254 #[wasm_bindgen(return_description = "The vector object being built with the shift operation.")]
1256 pub fn shift(
1257 mut self,
1258 #[wasm_bindgen(param_description = "The x-coordinate to translate the vector object by.")]
1259 dx: f32,
1260 #[wasm_bindgen(param_description = "The y-coordinate to translate the vector object by.")]
1261 dy: f32,
1262 #[wasm_bindgen(param_description = "Whether to apply the shift operation to the children of the vector object, default is true.")]
1263 recursive: Option<bool>
1264 ) -> VectorObjectBuilder {
1265 let shift = Box::new(Shift { dx, dy, recursive });
1266 self.ops.add_operation(Box::leak(shift));
1267 self
1268 }
1269 #[wasm_bindgen(return_description = "The vector object being built with the move to operation.")]
1271 pub fn move_to(
1272 mut self,
1273 #[wasm_bindgen(param_description = "The point to center the vector object at.")]
1274 point: Point2D,
1275 #[wasm_bindgen(param_description = "Whether to apply the move to operation to the children of the vector object.")]
1276 recursive: Option<bool>
1277 ) -> VectorObjectBuilder {
1278 let move_to = Box::new(MoveTo { point, recursive });
1279 self.ops.add_operation(Box::leak(move_to));
1280 self
1281 }
1282 #[wasm_bindgen(return_description = "The vector object being built with the scale operation.")]
1284 pub fn scale(
1285 mut self,
1286 #[wasm_bindgen(param_description = "The factor to scale the vector object by.")]
1287 factor_x: f32,
1288 #[wasm_bindgen(param_description = "The factor to scale the vector object by.")]
1289 factor_y: f32,
1290 #[wasm_bindgen(param_description = "The point to scale the vector object about.")]
1291 about_point: Option<Point2D>,
1292 #[wasm_bindgen(param_description = "Whether to apply the scale operation to the children of the vector object, default is true.")]
1293 recursive: Option<bool>
1294 ) -> VectorObjectBuilder {
1295 let scale = Box::new(Scale { factor_x, factor_y, about_point, recursive });
1296 self.ops.add_operation(Box::leak(scale));
1297 self
1298 }
1299 #[wasm_bindgen(return_description = "The vector object being built with the scale to width operation.")]
1301 pub fn scale_to_width(
1302 mut self,
1303 #[wasm_bindgen(param_description = "The width to scale the vector object to.")]
1304 width: f32,
1305 #[wasm_bindgen(param_description = "Whether to stretch the vector object to the given width, default is false.")]
1306 stretch: Option<bool>,
1307 #[wasm_bindgen(param_description = "The point to scale the vector object about, default is the center of the bounding box.")]
1308 about_point: Option<Point2D>,
1309 #[wasm_bindgen(param_description = "Whether to apply the scale to width operation to the children of the vector object, default is true.")]
1310 recursive: Option<bool>
1311 ) -> VectorObjectBuilder {
1312 let scale_to_width = Box::new(ScaleToWidth { width, stretch, about_point, recursive });
1313 self.ops.add_operation(Box::leak(scale_to_width));
1314 self
1315 }
1316 #[wasm_bindgen(return_description = "The vector object being built with the scale to height operation.")]
1318 pub fn scale_to_height(
1319 mut self,
1320 #[wasm_bindgen(param_description = "The height to scale the vector object to.")]
1321 height: f32,
1322 #[wasm_bindgen(param_description = "Whether to stretch the vector object to the given height, default is false.")]
1323 stretch: Option<bool>,
1324 #[wasm_bindgen(param_description = "The point to scale the vector object about, default is the center of the bounding box.")]
1325 about_point: Option<Point2D>,
1326 #[wasm_bindgen(param_description = "Whether to apply the scale to height operation to the children of the vector object, default is true.")]
1327 recursive: Option<bool>
1328 ) -> VectorObjectBuilder {
1329 let scale_to_height = Box::new(ScaleToHeight { height, stretch, about_point, recursive });
1330 self.ops.add_operation(Box::leak(scale_to_height));
1331 self
1332 }
1333 #[wasm_bindgen(return_description = "The vector object being built with the rotate operation.")]
1335 pub fn rotate(
1336 mut self,
1337 #[wasm_bindgen(param_description = "The angle in radians to rotate the vector object by.")]
1338 angle: f32,
1339 #[wasm_bindgen(param_description = "The point to rotate the vector object about, default is the center of the bounding box.")]
1340 from_point: Option<Point2D>,
1341 #[wasm_bindgen(param_description = "Whether to apply the rotate operation to the children of the vector object, default is true.")]
1342 recursive: Option<bool>
1343 ) -> VectorObjectBuilder {
1344 let rotate = Box::new(Rotate { angle, from_point, recursive });
1345 self.ops.add_operation(Box::leak(rotate));
1346 self
1347 }
1348 #[wasm_bindgen(return_description = "The vector object being built with the transform operation.")]
1350 pub fn set_transform(
1351 mut self,
1352 #[wasm_bindgen(param_description = "The matrix in CSS format to transform the vector object by.")]
1353 matrix: TransformationMatrix,
1354 #[wasm_bindgen(param_description = "Whether to apply the transform operation to the children of the vector object.")]
1355 recursive: Option<bool>
1356 ) -> VectorObjectBuilder {
1357 let transform = Box::new(SetTransform { matrix: matrix.clone(), recursive });
1358 self.ops.add_operation(Box::leak(transform));
1359 self
1360 }
1361 #[wasm_bindgen(return_description = "The vector object being built with the apply transform operation.")]
1363 pub fn apply_transform(
1364 mut self,
1365 #[wasm_bindgen(param_description = "The matrix in CSS format to apply to the vector object.")]
1366 matrix: TransformationMatrix,
1367 #[wasm_bindgen(param_description = "Whether to apply the apply transform operation to the children of the vector object, default is true.")]
1368 recursive: Option<bool>
1369 ) -> VectorObjectBuilder {
1370 let apply_transform = Box::new(ApplyTransform { matrix, recursive });
1371 self.ops.add_operation(Box::leak(apply_transform));
1372 self
1373 }
1374 #[wasm_bindgen(return_description = "The vector object being built with the add children operation.")]
1376 pub fn add_children(
1377 mut self,
1378 #[wasm_bindgen(param_description = "The children to add at the end of the vector object.")]
1379 children: Vec<VectorObjectBuilder>
1380 ) -> VectorObjectBuilder {
1381 let add_children = Box::new(AddChildren { children });
1382 self.ops.add_operation(Box::leak(add_children));
1383 self
1384 }
1385 #[wasm_bindgen(return_description = "The vector object being built with the insert child operation.")]
1387 pub fn insert_child(
1388 mut self,
1389 #[wasm_bindgen(param_description = "The index to insert the child at.")]
1390 index: usize,
1391 #[wasm_bindgen(param_description = "The child to insert into the vector object.")]
1392 child: VectorObjectBuilder
1393 ) -> VectorObjectBuilder {
1394 let insert_child = Box::new(InsertChild { index, child });
1395 self.ops.add_operation(Box::leak(insert_child));
1396 self
1397 }
1398 #[wasm_bindgen(return_description = "The vector object being built with the insert children operation.")]
1400 pub fn insert_children(
1401 mut self,
1402 #[wasm_bindgen(param_description = "The index to insert the children at.")]
1403 index: usize,
1404 #[wasm_bindgen(param_description = "The children to insert into the vector object.")]
1405 children: Vec<VectorObjectBuilder>
1406 ) -> VectorObjectBuilder {
1407 let insert_children = Box::new(InsertChildren { index, children });
1408 self.ops.add_operation(Box::leak(insert_children));
1409 self
1410 }
1411 #[wasm_bindgen(return_description = "The vector object being built with the remove child by index operation.")]
1413 pub fn remove_child_by_index(
1414 mut self,
1415 #[wasm_bindgen(param_description = "The index of the child to remove from the vector object.")]
1416 index: usize
1417 ) -> VectorObjectBuilder {
1418 let remove_child_by_index = Box::new(RemoveChildByIndex { index });
1419 self.ops.add_operation(Box::leak(remove_child_by_index));
1420 self
1421 }
1422 #[wasm_bindgen(return_description = "The vector object being built with the remove child by name operation.")]
1424 pub fn remove_child_by_name(
1425 mut self,
1426 #[wasm_bindgen(param_description = "The name of the child to remove from the vector object.")]
1427 name: String
1428 ) -> VectorObjectBuilder {
1429 let remove_child_by_name = Box::new(RemoveChildByName { name: Rc::new(name) });
1430 self.ops.add_operation(Box::leak(remove_child_by_name));
1431 self
1432 }
1433 #[wasm_bindgen(return_description = "The vector object being built with the match style properties operation.")]
1435 pub fn match_style_properties(
1436 mut self,
1437 #[wasm_bindgen(param_description = "The vector object to match the style properties of.")]
1438 vector_object_builder: VectorObjectBuilder
1439 ) -> VectorObjectBuilder {
1440 let match_style_properties = Box::new(MatchStyleProperties { vector_object_builder });
1441 self.ops.add_operation(Box::leak(match_style_properties));
1442 self
1443 }
1444 #[wasm_bindgen(return_description = "The vector object being built with the set actual path operation.")]
1446 pub fn set_actual_path(
1447 mut self,
1448 #[wasm_bindgen(param_description = "The path to set the vector object to.")]
1449 actual_path: Path2D
1450 ) -> VectorObjectBuilder {
1451 let set_actual_path = Box::new(SetActualPath { path: actual_path });
1452 self.ops.add_operation(Box::leak(set_actual_path));
1453 self
1454 }
1455 #[wasm_bindgen(return_description = "The vector object being built with the become partial operation.")]
1457 pub fn become_partial(
1458 mut self,
1459 #[wasm_bindgen(param_description = "The proportion of the path to start at.")]
1460 start: f32,
1461 #[wasm_bindgen(param_description = "The proportion of the path to end at.")]
1462 end: f32,
1463 #[wasm_bindgen(param_description = "Number of samples to compute the length of each cubic bezier curve segment.")]
1464 samples: Option<usize>,
1465 #[wasm_bindgen(param_description = "Extra length to add to each length computation to ensure the path is not too short.")]
1466 extra_length: Option<f32>,
1467 #[wasm_bindgen(param_description = "Whether to apply the become partial operation to the children of the vector object, default is true")]
1468 recursive: Option<bool>
1469 ) -> VectorObjectBuilder {
1470 let become_partial = Box::new(BecomePartial { start, end, samples, extra_length, recursive });
1471 self.ops.add_operation(Box::leak(become_partial));
1472 self
1473 }
1474 pub fn pointwise_become_partial(
1476 mut self,
1477 #[wasm_bindgen(param_description = "The proportion of the path to start at.")]
1478 start: f32,
1479 #[wasm_bindgen(param_description = "The proportion of the path to end at.")]
1480 end: f32,
1481 #[wasm_bindgen(param_description = "Whether to apply the pointwise become partial operation to the children of the vector object, default is true")]
1482 recursive: Option<bool>
1483 ) -> VectorObjectBuilder {
1484 let pointwise_become_partial = Box::new(PointwiseBecomePartial { start, end, recursive });
1485 self.ops.add_operation(Box::leak(pointwise_become_partial));
1486 self
1487 }
1488 #[wasm_bindgen(return_description = "The vector object being built with the move point operation.")]
1490 pub fn move_point(
1491 mut self,
1492 #[wasm_bindgen(param_description = "The point to start a new bezier curve at.")]
1493 point: &Point2D
1494 ) -> VectorObjectBuilder {
1495 let move_point = Box::new(MovePoint { point: *point });
1496 self.ops.add_operation(Box::leak(move_point));
1497 self
1498 }
1499 #[wasm_bindgen(return_description = "The vector object being built with the line to operation.")]
1501 pub fn line_to(
1502 mut self,
1503 #[wasm_bindgen(param_description = "The point to draw a line to.")]
1504 p: &Point2D
1505 ) -> VectorObjectBuilder {
1506 let line_to = Box::new(LineTo { point: *p });
1507 self.ops.add_operation(Box::leak(line_to));
1508 self
1509 }
1510 #[wasm_bindgen(return_description = "The vector object being built with the quadratic curve to operation.")]
1512 pub fn quadratic_curve_to(
1513 mut self,
1514 #[wasm_bindgen(param_description = "The control point of the quadratic curve.")]
1515 p1: &Point2D,
1516 #[wasm_bindgen(param_description = "The end point of the quadratic curve.")]
1517 p2: &Point2D
1518 ) -> VectorObjectBuilder {
1519 let quadratic_curve_to = Box::new(QuadraticCurveTo { p1: *p1, p2: *p2 });
1520 self.ops.add_operation(Box::leak(quadratic_curve_to));
1521 self
1522 }
1523 #[wasm_bindgen(return_description = "The vector object being built with the bezier curve to operation.")]
1525 pub fn bezier_curve_to(
1526 mut self,
1527 #[wasm_bindgen(param_description = "The first control point of the bezier curve.")]
1528 p1: &Point2D,
1529 #[wasm_bindgen(param_description = "The second control point of the bezier curve.")]
1530 p2: &Point2D,
1531 #[wasm_bindgen(param_description = "The end point of the bezier curve.")]
1532 p3: &Point2D
1533 ) -> VectorObjectBuilder {
1534 let bezier_curve_to = Box::new(BezierCurveTo { p1: *p1, p2: *p2, p3: *p3 });
1535 self.ops.add_operation(Box::leak(bezier_curve_to));
1536 self
1537 }
1538 #[wasm_bindgen(return_description = "The vector object being built with the close operation.")]
1540 pub fn close(mut self) -> VectorObjectBuilder {
1541 let close = Box::new(Close {});
1542 self.ops.add_operation(Box::leak(close));
1543 self
1544 }
1545 #[wasm_bindgen(return_description = "The vector object being built with the fade fill operation.")]
1547 pub fn fade_fill(
1548 mut self,
1549 #[wasm_bindgen(param_description = "The factor to fade the fill style by.")]
1550 factor: f32,
1551 #[wasm_bindgen(param_description = "Whether to apply the fade fill operation to the children of the vector object.")]
1552 recursive: Option<bool>
1553 ) -> VectorObjectBuilder {
1554 let fade_fill = Box::new(FadeFill { factor, recursive });
1555 self.ops.add_operation(Box::leak(fade_fill));
1556 self
1557 }
1558 #[wasm_bindgen(return_description = "The vector object being built with the fade stroke operation.")]
1560 pub fn fade_stroke(
1561 mut self,
1562 #[wasm_bindgen(param_description = "The factor to fade the stroke style by.")]
1563 factor: f32,
1564 #[wasm_bindgen(param_description = "Whether to apply the fade stroke operation to the children of the vector object.")]
1565 recursive: Option<bool>
1566 ) -> VectorObjectBuilder {
1567 let fade_stroke = Box::new(FadeStroke { factor, recursive });
1568 self.ops.add_operation(Box::leak(fade_stroke));
1569 self
1570 }
1571 #[wasm_bindgen(return_description = "The vector object being built with the set path operation.")]
1573 pub fn set_path(
1574 mut self,
1575 #[wasm_bindgen(param_description = "The path to set the vector object to.")]
1576 path: Path2D
1577 ) -> VectorObjectBuilder {
1578 let set_path = Box::new(SetPath { path });
1579 self.ops.add_operation(Box::leak(set_path));
1580 self
1581 }
1582 #[wasm_bindgen(return_description = "The vector object being built with the set fill operation.")]
1584 pub fn set_fill(
1585 mut self,
1586 #[wasm_bindgen(param_description = "The fill style to set the vector object to.")]
1587 fill: Style,
1588 #[wasm_bindgen(param_description = "Whether to apply the set fill operation to the children of the vector object, default is true.")]
1589 recursive: Option<bool>
1590 ) -> VectorObjectBuilder {
1591 let set_fill = Box::new(SetFill { fill, recursive });
1592 self.ops.add_operation(Box::leak(set_fill));
1593 self
1594 }
1595 #[wasm_bindgen(return_description = "The vector object being built with the set fill rule operation.")]
1597 pub fn set_fill_rule(
1598 mut self,
1599 #[wasm_bindgen(param_description = "The fill rule to set the vector object to.")]
1600 fill_rule: String,
1601 #[wasm_bindgen(param_description = "Whether to apply the set fill rule operation to the children of the vector object, default is true.")]
1602 recursive: Option<bool>
1603 ) -> VectorObjectBuilder {
1604 let set_fill_rule = Box::new(SetFillRule { fill_rule: Rc::new(fill_rule), recursive });
1605 self.ops.add_operation(Box::leak(set_fill_rule));
1606 self
1607 }
1608 #[wasm_bindgen(return_description = "The vector object being built with the set stroke operation.")]
1610 pub fn set_stroke(
1611 mut self,
1612 #[wasm_bindgen(param_description = "The stroke style to set the vector object to.")]
1613 stroke: Style,
1614 #[wasm_bindgen(param_description = "Whether to apply the set stroke operation to the children of the vector object, default is true.")]
1615 recursive: Option<bool>
1616 ) -> VectorObjectBuilder {
1617 let set_stroke = Box::new(SetStroke { stroke, recursive });
1618 self.ops.add_operation(Box::leak(set_stroke));
1619 self
1620 }
1621 #[wasm_bindgen(return_description = "The vector object being built with the set stroke width operation.")]
1623 pub fn set_stroke_width(
1624 mut self,
1625 #[wasm_bindgen(param_description = "The stroke width to set the vector object to.")]
1626 stroke_width: f32,
1627 #[wasm_bindgen(param_description = "Whether to apply the set stroke width operation to the children of the vector object, default is true.")]
1628 recursive: Option<bool>
1629 ) -> VectorObjectBuilder {
1630 let set_stroke_width = Box::new(SetStrokeWidth { stroke_width, recursive });
1631 self.ops.add_operation(Box::leak(set_stroke_width));
1632 self
1633 }
1634 #[wasm_bindgen(return_description = "The vector object being built with the set stroke line cap operation.")]
1636 pub fn set_stroke_line_cap(
1637 mut self,
1638 #[wasm_bindgen(param_description = "The stroke line cap to set the vector object to.")]
1639 stroke_line_cap: String,
1640 #[wasm_bindgen(param_description = "Whether to apply the set stroke line cap operation to the children of the vector object, default is true.")]
1641 recursive: Option<bool>
1642 ) -> VectorObjectBuilder {
1643 let set_stroke_line_cap = Box::new(SetStrokeLineCap { stroke_line_cap: Rc::new(stroke_line_cap), recursive });
1644 self.ops.add_operation(Box::leak(set_stroke_line_cap));
1645 self
1646 }
1647 #[wasm_bindgen(return_description = "The vector object being built with the set stroke line join operation.")]
1649 pub fn set_stroke_line_join(
1650 mut self,
1651 #[wasm_bindgen(param_description = "The stroke line join to set the vector object to.")]
1652 stroke_line_join: String,
1653 #[wasm_bindgen(param_description = "Whether to apply the set stroke line join operation to the children of the vector object, default is true.")]
1654 recursive: Option<bool>
1655 ) -> VectorObjectBuilder {
1656 let set_stroke_line_join = Box::new(SetStrokeLineJoin { stroke_line_join: Rc::new(stroke_line_join), recursive });
1657 self.ops.add_operation(Box::leak(set_stroke_line_join));
1658 self
1659 }
1660 #[wasm_bindgen(return_description = "The vector object being built with the set stroke miter limit operation.")]
1662 pub fn set_stroke_miter_limit(
1663 mut self,
1664 #[wasm_bindgen(param_description = "The stroke miter limit to set the vector object to.")]
1665 stroke_miter_limit: f32,
1666 #[wasm_bindgen(param_description = "Whether to apply the set stroke miter limit operation to the children of the vector object, default is true.")]
1667 recursive: Option<bool>
1668 ) -> VectorObjectBuilder {
1669 let set_stroke_miter_limit = Box::new(SetStrokeMiterLimit { stroke_miter_limit, recursive });
1670 self.ops.add_operation(Box::leak(set_stroke_miter_limit));
1671 self
1672 }
1673 #[wasm_bindgen(return_description = "The vector object being built with the set stroke dash offset operation.")]
1675 pub fn set_stroke_dash_offset(
1676 mut self,
1677 #[wasm_bindgen(param_description = "The stroke dash offset to set the vector object to.")]
1678 stroke_dash_offset: f32,
1679 #[wasm_bindgen(param_description = "Whether to apply the set stroke dash offset operation to the children of the vector object, default is true.")]
1680 recursive: Option<bool>
1681 ) -> VectorObjectBuilder {
1682 let set_stroke_dash_offset = Box::new(SetStrokeDashOffset { stroke_dash_offset, recursive });
1683 self.ops.add_operation(Box::leak(set_stroke_dash_offset));
1684 self
1685 }
1686 #[wasm_bindgen(return_description = "The vector object being built with the set stroke dash array operation.")]
1688 pub fn set_stroke_dash_array(
1689 mut self,
1690 #[wasm_bindgen(param_description = "The stroke dash array to set the vector object to.", unchecked_param_type = "number[]")]
1691 stroke_dash_array: Vec<f32>,
1692 #[wasm_bindgen(param_description = "Whether to apply the set stroke dash array operation to the children of the vector object, default is true.")]
1693 recursive: Option<bool>
1694 ) -> VectorObjectBuilder {
1695 let set_stroke_dash_array = Box::new(SetStrokeDashArray { stroke_dash_array: Rc::new(stroke_dash_array), recursive });
1696 self.ops.add_operation(Box::leak(set_stroke_dash_array));
1697 self
1698 }
1699 #[wasm_bindgen(return_description = "The vector object being built with the set children operation.")]
1701 pub fn set_children(
1702 mut self,
1703 #[wasm_bindgen(param_description = "The children to set the vector object to.")]
1704 children: Vec<VectorObjectBuilder>
1705 ) -> VectorObjectBuilder {
1706 let set_children = Box::new(SetChildren { children });
1707 self.ops.add_operation(Box::leak(set_children));
1708 self
1709 }
1710 #[wasm_bindgen(return_description = "The vector object being built with the set name operation.")]
1712 pub fn set_name(
1713 mut self,
1714 #[wasm_bindgen(param_description = "The name to set the vector object to.")]
1715 name: Option<String>
1716 ) -> VectorObjectBuilder {
1717 let set_name = Box::new(SetName { name: name.map(Rc::new) });
1718 self.ops.add_operation(Box::leak(set_name));
1719 self
1720 }
1721 #[wasm_bindgen(return_description = "The vector object being built with the apply transformation operation.")]
1723 pub fn actual_path_as_path(
1724 mut self,
1725 #[wasm_bindgen(param_description = "Whether to remove transformations after applying the current transformation to the path, default is true.")]
1726 untransform: Option<bool>,
1727 #[wasm_bindgen(param_description = "Whether to apply the actual path as path operation to the children of the vector object, default is true.")]
1728 recursive: Option<bool>
1729 ) -> VectorObjectBuilder {
1730 let actual_path_as_path = Box::new(ActualPathAsPath { untransform, recursive });
1731 self.ops.add_operation(Box::leak(actual_path_as_path));
1732 self
1733 }
1734 #[wasm_bindgen(return_description = "The vector object being built with the add child operation.")]
1736 pub fn add_child(
1737 mut self,
1738 #[wasm_bindgen(param_description = "The child to add to the vector object.")]
1739 child: VectorObjectBuilder
1740 ) -> VectorObjectBuilder {
1741 let add_child = Box::new(AddChild { child });
1742 self.ops.add_operation(Box::leak(add_child));
1743 self
1744 }
1745 #[wasm_bindgen(return_description = "The vector object being built with the remove children at indices operation.")]
1747 pub fn remove_children_at_indices(
1748 mut self,
1749 #[wasm_bindgen(param_description = "The indices of the children to remove from the vector object.", unchecked_param_type = "number[]")]
1750 indices: Vec<usize>
1751 ) -> VectorObjectBuilder {
1752 let remove_children_at_indices = Box::new(RemoveChildrenAtIndices { indices });
1753 self.ops.add_operation(Box::leak(remove_children_at_indices));
1754 self
1755 }
1756 #[wasm_bindgen(return_description = "The vector object being built with the remove children by names operation.")]
1758 pub fn remove_children_by_names(
1759 mut self,
1760 #[wasm_bindgen(param_description = "The names of the children to remove from the vector object.", unchecked_param_type = "string[]")]
1761 names: Vec<String>
1762 ) -> VectorObjectBuilder {
1763 let remove_children_by_names = Box::new(RemoveChildrenByNames { names });
1764 self.ops.add_operation(Box::leak(remove_children_by_names));
1765 self
1766 }
1767 #[wasm_bindgen(return_description = "The vector object being built with the set slice children operation.")]
1769 pub fn set_slice_children(
1770 mut self,
1771 #[wasm_bindgen(param_description = "The start index of the children to replace.")]
1772 start: usize,
1773 #[wasm_bindgen(param_description = "The end index of the children to replace.")]
1774 end: usize,
1775 #[wasm_bindgen(param_description = "The children to replace the children from the start index to the end index with.")]
1776 children: Vec<VectorObjectBuilder>
1777 ) -> VectorObjectBuilder {
1778 let set_slice_children = Box::new(SetSliceChildren { start, end, children });
1779 self.ops.add_operation(Box::leak(set_slice_children));
1780 self
1781 }
1782 #[wasm_bindgen(return_description = "The vector object being built with the next to point operation.")]
1784 pub fn next_to_point(
1785 mut self,
1786 #[wasm_bindgen(param_description = "The point to translate the vector object to.")]
1787 point: Point2D,
1788 #[wasm_bindgen(param_description = "The direction to translate the vector object in. If not given, the vector object will be at the right of the point, default is right.")]
1789 direction: Option<Point2D>,
1790 #[wasm_bindgen(param_description = "The buffer to leave between the vector object and the point. If not given, the vector object will be touching the point, default is 0.")]
1791 buff: Option<f32>,
1792 #[wasm_bindgen(param_description = "The edge of the vector object to align with the point. If not given, the vector object will be aligned at the middle, default is the middle.")]
1793 aligned_edge: Option<Point2D>,
1794 #[wasm_bindgen(param_description = "Whether to apply the next to point operation to the children of the vector object. If not given, the operation will be applied to the children, default is true.")]
1795 recursive: Option<bool>
1796 ) -> VectorObjectBuilder {
1797 let next_to_point = Box::new(NextToPoint { point, direction, buff, aligned_edge, recursive });
1798 self.ops.add_operation(Box::leak(next_to_point));
1799 self
1800 }
1801 #[wasm_bindgen(return_description = "The vector object being built with the next to other operation.")]
1803 pub fn next_to_other(
1804 mut self,
1805 #[wasm_bindgen(param_description = "The other vector object to translate the vector object to.")]
1806 other: VectorObjectBuilder,
1807 #[wasm_bindgen(param_description = "The direction to translate the vector object in. If not given, the vector object will be at the right of the other vector object, default is right.")]
1808 direction: Option<Point2D>,
1809 #[wasm_bindgen(param_description = "The buffer to leave between the vector object and the other vector object. If not given, the vector object will be touching the other vector object, default is 0.")]
1810 buff: Option<f32>,
1811 #[wasm_bindgen(param_description = "The edge of the vector object to align with the other vector object. If not given, the vector object will be aligned at the middle, default is the middle.")]
1812 aligned_edge: Option<Point2D>,
1813 #[wasm_bindgen(param_description = "Whether to apply the next to other operation to the children of the vector object. If not given, the operation will be applied to the children, default is true.")]
1814 recursive: Option<bool>
1815 ) -> VectorObjectBuilder {
1816 let next_to_other = Box::new(NextToOther { other, direction, buff, aligned_edge, recursive });
1817 self.ops.add_operation(Box::leak(next_to_other));
1818 self
1819 }
1820 #[wasm_bindgen(return_description = "The vector object being built with the arrange subobjects operation.")]
1822 pub fn arrange_children(
1823 mut self,
1824 #[wasm_bindgen(param_description = "The direction to arrange the children. If not given, the children will be arranged horizontally in the positive x direction.")]
1825 direction: Option<Point2D>,
1826 #[wasm_bindgen(param_description = "The buffer to leave between the children. If not given, the children will be touching, default is 0.")]
1827 buff: Option<f32>,
1828 #[wasm_bindgen(param_description = "The edge of the children to align with the point. If not given, the children will be aligned at the middle.")]
1829 aligned_edge: Option<Point2D>,
1830 #[wasm_bindgen(param_description = "The center of the children. If not given, the children won't be centered at any point.")]
1831 center: Option<Point2D>,
1832 #[wasm_bindgen(param_description = "Whether to apply the arrange subobjects operation to the children of the vector object, default is true.")]
1833 recursive: Option<bool>
1834 ) -> VectorObjectBuilder {
1835 let arrange_subobjects = Box::new(ArrangeChildren { direction, buff, aligned_edge, center, recursive });
1836 self.ops.add_operation(Box::leak(arrange_subobjects));
1837 self
1838 }
1839 #[wasm_bindgen(return_description = "The vector object being built with the reverse path operation.")]
1841 pub fn reverse_path(mut self) -> VectorObjectBuilder {
1842 let reverse_path = Box::new(ReversePath {});
1843 self.ops.add_operation(Box::leak(reverse_path));
1844 self
1845 }
1846 #[wasm_bindgen(return_description = "The vector object being built with the interpolate fill operation.")]
1848 pub fn lerp_fill(
1849 mut self,
1850 #[wasm_bindgen(param_description = "The vector object to interpolate the fill style with.")]
1851 fill: Style,
1852 #[wasm_bindgen(param_description = "The factor to interpolate the fill style by.")]
1853 t: f32,
1854 #[wasm_bindgen(param_description = "The image's top left corner x-coordinate. It must be provided if the fill style contains an image or different kinds of gradients.")]
1855 x: Option<f32>,
1856 #[wasm_bindgen(param_description = "The image's top left corner y-coordinate. It must be provided if the fill style contains an image or different kinds of gradients.")]
1857 y: Option<f32>,
1858 #[wasm_bindgen(param_description = "The image's rendering width. It must be provided if the fill style contains an image or different kinds of gradients.")]
1859 width: Option<f32>,
1860 #[wasm_bindgen(param_description = "The image's rendering height. It must be provided if the fill style contains an image or different kinds of gradients.")]
1861 height: Option<f32>,
1862 #[wasm_bindgen(param_description = "The image's number of pixels in a row. It must be provided if the fill style contains an image or different kinds of gradients.")]
1863 data_width: Option<usize>,
1864 #[wasm_bindgen(param_description = "The image's number of pixels in a column. It must be provided if the fill style contains an image or different kinds of gradients.")]
1865 data_height: Option<usize>,
1866 #[wasm_bindgen(param_description = "Whether to apply the interpolate fill operation to the children of the vector object, default is true.")]
1867 recursive: Option<bool>,
1868 ) -> VectorObjectBuilder {
1869 let interpolate_fill = Box::new(LerpFill { fill, t, x, y, width, height, data_width, data_height, recursive });
1870 self.ops.add_operation(Box::leak(interpolate_fill));
1871 self
1872 }
1873 #[wasm_bindgen(return_description = "The vector object being built with the interpolate stroke operation.")]
1875 pub fn lerp_stroke(
1876 mut self,
1877 #[wasm_bindgen(param_description = "The vector object to interpolate the stroke style with.")]
1878 stroke: Style,
1879 #[wasm_bindgen(param_description = "The factor to interpolate the stroke style by.")]
1880 t: f32,
1881 #[wasm_bindgen(param_description = "The image's top left corner x-coordinate. It must be provided if the stroke style contains an image or different kinds of gradients.")]
1882 x: Option<f32>,
1883 #[wasm_bindgen(param_description = "The image's top left corner y-coordinate. It must be provided if the stroke style contains an image or different kinds of gradients.")]
1884 y: Option<f32>,
1885 #[wasm_bindgen(param_description = "The image's rendering width. It must be provided if the stroke style contains an image or different kinds of gradients.")]
1886 width: Option<f32>,
1887 #[wasm_bindgen(param_description = "The image's rendering height. It must be provided if the stroke style contains an image or different kinds of gradients.")]
1888 height: Option<f32>,
1889 #[wasm_bindgen(param_description = "The image's number of pixels in a row. It must be provided if the stroke style contains an image or different kinds of gradients.")]
1890 data_width: Option<usize>,
1891 #[wasm_bindgen(param_description = "The image's number of pixels in a column. It must be provided if the stroke style contains an image or different kinds of gradients.")]
1892 data_height: Option<usize>,
1893 #[wasm_bindgen(param_description = "Whether to apply the interpolate stroke operation to the children of the vector object, default is true.")]
1894 recursive: Option<bool>,
1895 ) -> VectorObjectBuilder {
1896 let interpolate_stroke = Box::new(LerpStroke { stroke, t, x, y, width, height, data_width, data_height, recursive });
1897 self.ops.add_operation(Box::leak(interpolate_stroke));
1898 self
1899 }
1900 #[wasm_bindgen(return_description = "The vector object built by applying the operations to it.")]
1902 pub fn build(self) -> VectorObject {
1903 let mut vector_object = Rc::clone(&self.object);
1904 let vector_object_as_mut = Rc::make_mut(&mut vector_object);
1905 self.ops.apply_and_return(vector_object_as_mut)
1906 }
1907}
1908
1909impl VectorObjectBuilder {
1910 pub fn from_node(node: &usvg::Node) -> VectorObjectBuilder {
1911 let mut builder = VectorObjectBuilder::default();
1912 match node {
1913 usvg::Node::Path(ref path) => {
1914 builder = builder.add_child(VectorObjectBuilder::from_path(path));
1915 }
1916 usvg::Node::Group(ref group) => {
1917 builder = builder.add_child(VectorObjectBuilder::from_group(group));
1918 }
1919 usvg::Node::Text(ref text) => {
1920 builder = builder.add_child(VectorObjectBuilder::from_text(text));
1921 }
1922 usvg::Node::Image(ref image) => {
1923 builder = builder.add_child(VectorObjectBuilder::from_image(image));
1924 }
1925 }
1926 builder
1927 }
1928 pub fn from_path(internal_path: &usvg::Path) -> VectorObjectBuilder {
1929 let mut vector_object_builder = VectorObjectBuilder::default();
1930 let path = Path2D::from_svg_path_data(internal_path.data());
1931 vector_object_builder = vector_object_builder.set_path(path);
1932 let internal_fill_option = internal_path.fill();
1933 let fill;
1934 let fill_rule;
1935 if let Some(internal_fill) = internal_fill_option {
1936 fill = Style::from_paint_and_opacity(internal_fill.paint(), &internal_fill.opacity());
1937 fill_rule = match internal_fill.rule() {
1938 usvg::FillRule::NonZero => "nonzero",
1939 usvg::FillRule::EvenOdd => "evenodd",
1940 };
1941 } else {
1942 fill = Style::from_color(Color::new(0, 0, 0, 0.0));
1943 fill_rule = "nonzero";
1944 }
1945 vector_object_builder = vector_object_builder.set_fill(fill, Some(false)).set_fill_rule(fill_rule.to_string(), Some(false));
1946 let internal_stroke_option = internal_path.stroke();
1947 let stroke;
1948 let stroke_width;
1949 let stroke_line_cap;
1950 let stroke_line_join;
1951 let stroke_miter_limit;
1952 let stroke_dash_offset;
1953 let stroke_dash_array;
1954 if let Some(internal_stroke) = internal_stroke_option {
1955 stroke = Style::from_paint_and_opacity(internal_stroke.paint(), &internal_stroke.opacity());
1956 stroke_width = internal_stroke.width().get();
1957 stroke_line_cap = match internal_stroke.linecap() {
1958 usvg::LineCap::Butt => "butt",
1959 usvg::LineCap::Round => "round",
1960 usvg::LineCap::Square => "square",
1961 };
1962 stroke_line_join = match internal_stroke.linejoin() {
1963 usvg::LineJoin::Miter => "miter",
1964 usvg::LineJoin::Round => "round",
1965 usvg::LineJoin::Bevel => "bevel",
1966 usvg::LineJoin::MiterClip => "miter-clip",
1967 };
1968 stroke_miter_limit = internal_stroke.miterlimit().get();
1969 stroke_dash_offset = internal_stroke.dashoffset();
1970 stroke_dash_array = internal_stroke.dasharray().unwrap_or(&[]).to_vec();
1971 } else {
1972 stroke = Style::from_color(Color::new(0, 0, 0, 0.0));
1973 stroke_width = 1.0;
1974 stroke_line_cap = "butt";
1975 stroke_line_join = "miter";
1976 stroke_miter_limit = 4.0;
1977 stroke_dash_offset = 0.0;
1978 stroke_dash_array = Vec::new();
1979 }
1980 vector_object_builder = vector_object_builder.set_stroke(stroke, Some(false)).set_stroke_width(stroke_width, Some(false)).set_stroke_line_cap(stroke_line_cap.to_string(), Some(false)).set_stroke_line_join(stroke_line_join.to_string(), Some(false)).set_stroke_miter_limit(stroke_miter_limit, Some(false)).set_stroke_dash_offset(stroke_dash_offset, Some(false)).set_stroke_dash_array(stroke_dash_array, Some(false));
1981 let transform = TransformationMatrix::from_svg_transform(internal_path.abs_transform());
1982 vector_object_builder = vector_object_builder.set_transform(transform, Some(false));
1983 vector_object_builder
1984 }
1985 pub fn from_group(internal_group: &usvg::Group) -> VectorObjectBuilder {
1986 let mut vector_object_builder = VectorObjectBuilder::default();
1987 for node in internal_group.children() {
1988 vector_object_builder = vector_object_builder.add_child(VectorObjectBuilder::from_node(node));
1989 }
1990 let transform = TransformationMatrix::from_svg_transform(internal_group.abs_transform());
1991 vector_object_builder = vector_object_builder.set_transform(transform, Some(false));
1992 vector_object_builder
1993 }
1994 pub fn from_text(text: &usvg::Text) -> VectorObjectBuilder {
1995 VectorObjectBuilder::from_group(text.flattened())
1996 .apply_transform(TransformationMatrix::from_svg_transform(text.abs_transform()), None)
1997 }
1998 pub fn from_image(image: &usvg::Image) -> VectorObjectBuilder {
1999 let kind = image.kind();
2000 let dimensions = image.size();
2001 let data_width = dimensions.width().round() as usize;
2002 let data_height = dimensions.height().round() as usize;
2003 let data = match &kind {
2004 usvg::ImageKind::PNG(data) => {
2005 let image_data = data.to_vec();
2006 Some(image_data)
2007 }
2008 usvg::ImageKind::JPEG(data) => {
2009 let image_data = data.to_vec();
2010 Some(image_data)
2011 }
2012 usvg::ImageKind::WEBP(data) => {
2013 let image_data = data.to_vec();
2014 Some(image_data)
2015 }
2016 _ => None
2017 };
2018 if data.is_none() {
2019 log("Unsupported image format.");
2020 return VectorObjectBuilder::default();
2021 }
2022 let x = image.bounding_box().x();
2023 let y = image.bounding_box().y();
2024 let width = image.bounding_box().width();
2025 let height = image.bounding_box().height();
2026 let mut vector_object_builder = Rectangle::new(
2027 BoundingBox::new(x, y, width, height).unwrap(),
2028 None
2029 ).vector_object_builder().set_stroke_width(0.0, Some(false));
2030 let img = ImageBitmap::new(x, y, width, height, data_width, data_height, data.unwrap());
2031 if img.is_err() {
2032 log("Failed to create image bitmap.");
2033 return VectorObjectBuilder::default();
2034 }
2035 vector_object_builder = vector_object_builder.set_fill(
2036 Style::from_image(img.unwrap()),
2037 Some(false)
2038 );
2039 vector_object_builder = vector_object_builder.set_transform(
2040 TransformationMatrix::from_svg_transform(image.abs_transform()),
2041 Some(false)
2042 );
2043 vector_object_builder
2044 }
2045}
2046
2047#[wasm_bindgen]
2048impl VectorObject {
2049 #[wasm_bindgen(constructor, return_description = "A new vector object.")]
2051 pub fn new(
2052 #[wasm_bindgen(param_description = "The Path2D of the vector object.")]
2053 path: Path2D,
2054 #[wasm_bindgen(param_description = "The fill Style of the vector object.")]
2055 fill: Style,
2056 #[wasm_bindgen(param_description = "The fill rule of the vector object.")]
2057 fill_rule: String,
2058 #[wasm_bindgen(param_description = "The stroke Style of the vector object.")]
2059 stroke: Style,
2060 #[wasm_bindgen(param_description = "The stroke width of the vector object.")]
2061 stroke_width: f32,
2062 #[wasm_bindgen(param_description = "The stroke line cap of the vector object.")]
2063 stroke_line_cap: String,
2064 #[wasm_bindgen(param_description = "The stroke line join of the vector object.")]
2065 stroke_line_join: String,
2066 #[wasm_bindgen(param_description = "The stroke miter limit of the vector object.")]
2067 stroke_miter_limit: f32,
2068 #[wasm_bindgen(param_description = "The stroke dash offset of the vector object.")]
2069 stroke_dash_offset: f32,
2070 #[wasm_bindgen(param_description = "The stroke dash array of the vector object.", unchecked_param_type = "number[]")]
2071 stroke_dash_array: Vec<f32>,
2072 #[wasm_bindgen(param_description = "The children of the vector object.")]
2073 children: Vec<VectorObject>,
2074 #[wasm_bindgen(param_description = "The name of the vector object.")]
2075 name: Option<String>,
2076 #[wasm_bindgen(param_description = "The TransformationMatrix of the vector object.")]
2077 transform: TransformationMatrix
2078 ) -> VectorObject {
2079 VectorObject {
2080 path,
2081 fill,
2082 fill_rule: Rc::new(fill_rule),
2083 stroke,
2084 stroke_width,
2085 stroke_line_cap: Rc::new(stroke_line_cap),
2086 stroke_line_join: Rc::new(stroke_line_join),
2087 stroke_miter_limit,
2088 stroke_dash_offset,
2089 stroke_dash_array: Rc::new(stroke_dash_array),
2090 children,
2091 name: name.map(Rc::new),
2092 transform,
2093 }
2094 }
2095 #[wasm_bindgen(js_name = clone, return_description = "The cloned vector object.")]
2097 pub fn clone_js(&self) -> VectorObject {
2098 self.clone()
2099 }
2100 #[wasm_bindgen(return_description = "A new empty vector object.")]
2102 pub fn default_vector_object() -> VectorObject {
2103 VectorObject::default()
2104 }
2105 #[wasm_bindgen(getter, return_description = "The path of the vector object.")]
2107 pub fn path(&self) -> Path2D {
2108 self.path.clone()
2109 }
2110 #[wasm_bindgen(getter, return_description = "The fill style of the vector object.")]
2112 pub fn fill(&self) -> Style {
2113 self.fill.clone()
2114 }
2115 #[wasm_bindgen(getter, return_description = "The fill rule of the vector object.")]
2117 pub fn fill_rule(&self) -> String {
2118 self.fill_rule.to_string()
2119 }
2120 #[wasm_bindgen(getter, return_description = "The stroke style of the vector object.")]
2122 pub fn stroke(&self) -> Style {
2123 self.stroke.clone()
2124 }
2125 #[wasm_bindgen(getter, return_description = "The stroke width of the vector object.")]
2127 pub fn stroke_width(&self) -> f32 {
2128 self.stroke_width
2129 }
2130 #[wasm_bindgen(getter, return_description = "The stroke line cap of the vector object.")]
2132 pub fn stroke_line_cap(&self) -> String {
2133 self.stroke_line_cap.to_string()
2134 }
2135 #[wasm_bindgen(getter, return_description = "The stroke line join of the vector object.")]
2137 pub fn stroke_line_join(&self) -> String {
2138 self.stroke_line_join.to_string()
2139 }
2140 #[wasm_bindgen(getter, return_description = "The stroke miter limit of the vector object.")]
2142 pub fn stroke_miter_limit(&self) -> f32 {
2143 self.stroke_miter_limit
2144 }
2145 #[wasm_bindgen(getter, return_description = "The stroke dash offset of the vector object.")]
2147 pub fn stroke_dash_offset(&self) -> f32 {
2148 self.stroke_dash_offset
2149 }
2150 #[wasm_bindgen(getter, return_description = "The stroke dash array of the vector object.", unchecked_return_type = "number[]")]
2152 pub fn stroke_dash_array(&self) -> Vec<f32> {
2153 self.stroke_dash_array.to_vec()
2154 }
2155 #[wasm_bindgen(getter, return_description = "The children of the vector object.")]
2157 pub fn children(&self) -> Vec<VectorObject> {
2158 self.children.clone()
2159 }
2160 #[wasm_bindgen(getter, return_description = "The name of the vector object.")]
2162 pub fn name(&self) -> Option<String> {
2163 self.name.as_ref().map(|name| name.to_string())
2164 }
2165 #[wasm_bindgen(getter, return_description = "The transformation matrix of the vector object.")]
2167 pub fn transform(&self) -> TransformationMatrix {
2168 self.transform.clone()
2169 }
2170 #[wasm_bindgen(getter, return_description = "The path of the vector object with the applied transform.")]
2172 pub fn actual_path(&self) -> Path2D {
2173 self.path.transform(&self.transform)
2174 }
2175 #[wasm_bindgen(return_description = "The bounding box of the vector object.")]
2177 pub fn bounding_box(
2178 &self,
2179 #[wasm_bindgen(param_description = "Whether to include the children of the vector object.")]
2180 recursive: Option<bool>
2181 ) -> Option<BoundingBox> {
2182 let path = self.actual_path();
2183 let mut bbox = BoundingBox::from_path(&path);
2184 if recursive.unwrap_or(true) {
2185 for child in self.children.iter() {
2186 let child_bbox = child.bounding_box(Some(true));
2187 bbox = BoundingBox::union(bbox, child_bbox);
2188 }
2189 }
2190 bbox
2191 }
2192 #[wasm_bindgen(getter, return_description = "The center of the vector object.")]
2194 pub fn center(
2195 &self,
2196 ) -> Option<Point2D> {
2197 self.bounding_box(None).map(|bbox| bbox.center())
2198 }
2199 #[wasm_bindgen(return_description = "The critical point of the vector object.")]
2201 pub fn get_critical_point(
2202 &self,
2203 #[wasm_bindgen(param_description = "The x key of the critical point. If negative, the minimum x is returned. If positive, the maximum x is returned. If zero, the center x is returned.")]
2204 key_x: f32,
2205 #[wasm_bindgen(param_description = "The y key of the critical point. If negative, the minimum y is returned. If positive, the maximum y is returned. If zero, the center y is returned.")]
2206 key_y: f32,
2207 #[wasm_bindgen(param_description = "Whether to include the children of the vector object.")]
2208 recursive: Option<bool>
2209 ) -> Option<Point2D> {
2210 let bounding_box = self.bounding_box(recursive);
2211 if bounding_box.is_none() {
2212 return None;
2213 }
2214 let bounding_box = bounding_box.unwrap();
2215 let center = bounding_box.center();
2216 let min_x = bounding_box.min_x();
2217 let min_y = bounding_box.min_y();
2218 let width = bounding_box.width();
2219 let height = bounding_box.height();
2220 let x = if key_x < 0.0 {
2221 min_x
2222 } else if key_x > 0.0 {
2223 min_x + width
2224 } else {
2225 center.x
2226 };
2227 let y = if key_y < 0.0 {
2228 min_y
2229 } else if key_y > 0.0 {
2230 min_y + height
2231 } else {
2232 center.y
2233 };
2234 Some(Point2D { x, y })
2235 }
2236 #[wasm_bindgen(return_description = "The children of the vector object.")]
2238 pub fn get_children_recursive(
2239 &self,
2240 #[wasm_bindgen(param_description = "Whether to include the children of the children of the vector object, default is false.")]
2241 with_points: Option<bool>
2242 ) -> Vec<VectorObject> {
2243 let mut children = Vec::new();
2244 for child in self.children.iter() {
2245 if with_points.unwrap_or(false) {
2246 children.push(child.clone());
2247 }
2248 children.extend(child.get_children_recursive(with_points));
2249 }
2250 children
2251 }
2252 #[wasm_bindgen(getter, return_description = "The number of curves in the vector object.")]
2254 pub fn num_curves(&self) -> usize {
2255 self.path.len() / 4
2256 }
2257 #[wasm_bindgen(getter, return_description = "The number of points in the vector object.")]
2259 pub fn num_points(&self) -> usize {
2260 self.path.len()
2261 }
2262 #[wasm_bindgen(getter, return_description = "The number of children in the vector object.")]
2264 pub fn num_children(&self) -> usize {
2265 self.children.len()
2266 }
2267 #[wasm_bindgen(getter, return_description = "Whether the vector object's path is closed.")]
2269 pub fn is_closed(&self) -> bool {
2270 self.path[0].equals(&self.path[self.path.len() - 1], None)
2271 }
2272 #[wasm_bindgen(getter, return_description = "The subpaths of the vector object.")]
2274 pub fn subpaths(&self) -> Vec<Path2D> {
2275 let rng = (4..self.path.len()).step_by(4);
2276 let filtered = rng.filter(|&i| !self.path[i - 1].equals(&self.path[i], None)).collect::<Vec<usize>>();
2277 let split_indices = vec![0].into_iter().chain(filtered).chain(vec![self.path.len()]).collect::<Vec<usize>>();
2278 let subpaths = split_indices.iter().zip(split_indices[1..].iter()).filter(|(start, end)| *end - *start >= 4).map(|(start, end)| self.path.slice(*start, *end)).collect();
2279 subpaths
2280 }
2281 #[wasm_bindgen(getter, return_description = "The width of the vector object.")]
2283 pub fn width(&self) -> Option<f32> {
2284 self.bounding_box(None).map(|bbox| bbox.width())
2285 }
2286 #[wasm_bindgen(getter, return_description = "The height of the vector object.")]
2288 pub fn height(&self) -> Option<f32> {
2289 self.bounding_box(None).map(|bbox| bbox.height())
2290 }
2291 #[wasm_bindgen(return_description = "The sliced children of the vector object.")]
2293 pub fn slice_children(
2294 &self,
2295 #[wasm_bindgen(param_description = "The start index of the children to slice.")]
2296 start: usize,
2297 #[wasm_bindgen(param_description = "The end index of the children to slice.")]
2298 end: usize
2299 ) -> Vec<VectorObject> {
2300 self.children[start..end].to_vec()
2301 }
2302 #[wasm_bindgen(return_description = "The children with the given names.")]
2304 pub fn get_children_by_names(
2305 &self,
2306 #[wasm_bindgen(param_description = "The names of the children to get.", unchecked_param_type = "string[]")]
2307 names: Vec<String>
2308 ) -> Vec<VectorObject> {
2309 let mut children = Vec::new();
2310 for child in self.children.iter() {
2311 if let Some(name) = child.name() {
2312 if names.contains(&name) {
2313 children.push(child.clone());
2314 }
2315 }
2316 }
2317 children
2318 }
2319}
2320
2321impl VectorObject {
2322 pub fn apply_operation(&mut self, operation: &dyn VectorOperation) {
2323 operation.apply(self);
2324 }
2325}