1use crate::*;
2
3impl Camera2D {
5 pub fn create(viewport_width: f64, viewport_height: f64) -> Camera2D {
16 Camera2D::new(
17 Vector2D::zero(),
18 RENDERER_DEFAULT_CAMERA_ZOOM,
19 RENDERER_DEFAULT_CAMERA_ROTATION,
20 viewport_width,
21 viewport_height,
22 )
23 }
24
25 pub fn world_to_screen(&self, world: Vector2D) -> Vector2D {
35 let relative: Vector2D = world - self.get_position();
36 let rotated: Vector2D = relative.rotated(-self.get_rotation());
37 Vector2D::new(
38 rotated.get_x() * self.get_zoom() + self.get_viewport_width() * 0.5,
39 rotated.get_y() * self.get_zoom() + self.get_viewport_height() * 0.5,
40 )
41 }
42
43 pub fn screen_to_world(&self, screen: Vector2D) -> Vector2D {
53 let relative: Vector2D = Vector2D::new(
54 (screen.get_x() - self.get_viewport_width() * 0.5) / self.get_zoom(),
55 (screen.get_y() - self.get_viewport_height() * 0.5) / self.get_zoom(),
56 );
57 let rotated: Vector2D = relative.rotated(self.get_rotation());
58 rotated + self.get_position()
59 }
60
61 pub fn translate(&mut self, offset: Vector2D) {
67 self.set_position(self.get_position() + offset);
68 }
69
70 pub fn zoom_by(&mut self, factor: f64) {
76 self.set_zoom((self.get_zoom() * factor).max(EPSILON));
77 }
78}
79
80impl Default for Camera2D {
82 fn default() -> Camera2D {
83 Camera2D::create(800.0, 600.0)
84 }
85}
86
87impl CanvasRenderer {
89 pub fn build_font_string(size: f64, family: &str) -> String {
100 format!("{}px {}", size, family)
101 }
102
103 pub fn default_font_string() -> String {
109 Self::build_font_string(RENDERER_DEFAULT_FONT_SIZE, RENDERER_DEFAULT_FONT_FAMILY)
110 }
111
112 pub fn enable_context_anti_aliasing(context: &CanvasRenderingContext2d) {
122 let _ = Reflect::set(
123 context,
124 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_ENABLED),
125 &JsValue::from_bool(true),
126 );
127 let _ = Reflect::set(
128 context,
129 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_QUALITY),
130 &JsValue::from_str(RENDERER_IMAGE_SMOOTHING_QUALITY_HIGH),
131 );
132 let _ = Reflect::set(
133 context,
134 &JsValue::from_str(RENDERER_PROPERTY_TEXT_RENDERING),
135 &JsValue::from_str(RENDERER_TEXT_RENDERING_GEOMETRIC_PRECISION),
136 );
137 }
138}
139
140impl Color {
142 pub fn to_css(color: &Color) -> String {
152 color.to_css_rgba()
153 }
154}
155
156impl CanvasRenderer {
158 pub fn from_selector(
170 canvas_selector: &str,
171 viewport_width: f64,
172 viewport_height: f64,
173 ) -> Option<CanvasRenderer> {
174 let window_value: Window = window().expect("no global window exists");
175 let document_value: Document = window_value.document().expect("should have a document");
176 let element: Element = document_value
177 .query_selector(canvas_selector)
178 .ok()
179 .flatten()?;
180 let canvas_element: HtmlCanvasElement = element.unchecked_into();
181 let context_object: Object = canvas_element
182 .get_context(RENDERER_CONTEXT_TYPE_2D)
183 .ok()
184 .flatten()?;
185 let context: CanvasRenderingContext2d = context_object.unchecked_into();
186 Some(CanvasRenderer::new(
187 context,
188 Camera2D::create(viewport_width, viewport_height),
189 ))
190 }
191
192 pub fn enable_anti_aliasing(&self) {
199 let _ = Reflect::set(
200 self.get_context(),
201 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_ENABLED),
202 &JsValue::from_bool(true),
203 );
204 let _ = Reflect::set(
205 self.get_context(),
206 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_QUALITY),
207 &JsValue::from_str(RENDERER_IMAGE_SMOOTHING_QUALITY_HIGH),
208 );
209 }
210
211 pub fn clear(&self) {
213 self.get_context().clear_rect(
214 0.0,
215 0.0,
216 self.get_camera().get_viewport_width(),
217 self.get_camera().get_viewport_height(),
218 );
219 }
220
221 pub fn clear_with_color(&self, color: &str) {
227 let _ = Reflect::set(
228 self.get_context(),
229 &JsValue::from_str(RENDERER_PROPERTY_FILL_STYLE),
230 &JsValue::from_str(color),
231 );
232 self.get_context().fill_rect(
233 0.0,
234 0.0,
235 self.get_camera().get_viewport_width(),
236 self.get_camera().get_viewport_height(),
237 );
238 }
239
240 pub fn save(&self) {
242 self.get_context().save();
243 }
244
245 pub fn restore(&self) {
247 self.get_context().restore();
248 }
249
250 pub fn apply_camera(&self) {
255 let camera: Camera2D = self.get_camera();
256 let _ = self.get_context().translate(
257 camera.get_viewport_width() * 0.5,
258 camera.get_viewport_height() * 0.5,
259 );
260 let _ = self
261 .get_context()
262 .scale(camera.get_zoom(), camera.get_zoom());
263 let _ = self.get_context().rotate(camera.get_rotation());
264 let _ = self.get_context().translate(
265 -camera.get_position().get_x(),
266 -camera.get_position().get_y(),
267 );
268 }
269
270 pub fn set_fill_color(&self, color: &str) {
276 let _ = Reflect::set(
277 self.get_context(),
278 &JsValue::from_str(RENDERER_PROPERTY_FILL_STYLE),
279 &JsValue::from_str(color),
280 );
281 }
282
283 pub fn set_stroke_color(&self, color: &str) {
289 let _ = Reflect::set(
290 self.get_context(),
291 &JsValue::from_str(RENDERER_PROPERTY_STROKE_STYLE),
292 &JsValue::from_str(color),
293 );
294 }
295
296 pub fn set_line_width(&self, width: f64) {
302 let _ = Reflect::set(
303 self.get_context(),
304 &JsValue::from_str(RENDERER_PROPERTY_LINE_WIDTH),
305 &JsValue::from_f64(width),
306 );
307 }
308
309 pub fn set_global_alpha(&self, alpha: f64) {
315 let _ = Reflect::set(
316 self.get_context(),
317 &JsValue::from_str(RENDERER_PROPERTY_GLOBAL_ALPHA),
318 &JsValue::from_f64(Numeric::clamp(alpha, 0.0, 1.0)),
319 );
320 }
321
322 pub fn fill_rect(&self, position: Vector2D, width: f64, height: f64) {
330 self.get_context()
331 .fill_rect(position.get_x(), position.get_y(), width, height);
332 }
333
334 pub fn stroke_rect(&self, position: Vector2D, width: f64, height: f64) {
342 self.get_context()
343 .stroke_rect(position.get_x(), position.get_y(), width, height);
344 }
345
346 pub fn fill_circle(&self, center: Vector2D, radius: f64) {
353 self.get_context().begin_path();
354 self.get_context()
355 .arc(center.get_x(), center.get_y(), radius, 0.0, TWO_PI)
356 .unwrap_or(());
357 self.get_context().fill();
358 }
359
360 pub fn stroke_circle(&self, center: Vector2D, radius: f64) {
367 self.get_context().begin_path();
368 self.get_context()
369 .arc(center.get_x(), center.get_y(), radius, 0.0, TWO_PI)
370 .unwrap_or(());
371 self.get_context().stroke();
372 }
373
374 pub fn draw_line(&self, start: Vector2D, end: Vector2D) {
381 self.get_context().begin_path();
382 self.get_context().move_to(start.get_x(), start.get_y());
383 self.get_context().line_to(end.get_x(), end.get_y());
384 self.get_context().stroke();
385 }
386
387 pub fn fill_text(&self, text: &str, position: Vector2D) {
394 self.get_context()
395 .fill_text(text, position.get_x(), position.get_y())
396 .unwrap_or(());
397 }
398
399 pub fn set_font(&self, font: &str) {
405 let _ = Reflect::set(
406 self.get_context(),
407 &JsValue::from_str(RENDERER_PROPERTY_FONT),
408 &JsValue::from_str(font),
409 );
410 }
411
412 pub fn draw_image(
421 &self,
422 image: &HtmlImageElement,
423 position: Vector2D,
424 width: f64,
425 height: f64,
426 ) {
427 let _ = self
428 .get_context()
429 .draw_image_with_html_image_element_and_dw_and_dh(
430 image,
431 position.get_x(),
432 position.get_y(),
433 width,
434 height,
435 );
436 }
437
438 pub fn draw_image_subregion(
448 &self,
449 image: &HtmlImageElement,
450 source: Rect,
451 dest_position: Vector2D,
452 dest_width: f64,
453 dest_height: f64,
454 ) {
455 let _ = self
456 .get_context()
457 .draw_image_with_html_image_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh(
458 image,
459 source.get_x(),
460 source.get_y(),
461 source.get_width(),
462 source.get_height(),
463 dest_position.get_x(),
464 dest_position.get_y(),
465 dest_width,
466 dest_height,
467 );
468 }
469}
470
471impl Camera3D {
473 pub fn create(
486 position: Vector3D,
487 target: Vector3D,
488 viewport_width: f64,
489 viewport_height: f64,
490 ) -> Camera3D {
491 let mut camera: Camera3D = Camera3D::new(position, target, viewport_width, viewport_height);
492 camera.set_up(Vector3D::up());
493 camera.set_fov(DEFAULT_CAMERA_FOV);
494 camera.set_near(DEFAULT_CAMERA_NEAR);
495 camera.set_far(DEFAULT_CAMERA_FAR);
496 camera
497 }
498
499 pub fn aspect(&self) -> f64 {
505 if self.get_viewport_height() < EPSILON {
506 return 1.0;
507 }
508 self.get_viewport_width() / self.get_viewport_height()
509 }
510
511 pub fn forward(&self) -> Vector3D {
517 (self.get_target() - self.get_position()).normalized()
518 }
519
520 pub fn right(&self) -> Vector3D {
526 self.forward().cross(self.get_up()).normalized()
527 }
528
529 pub fn view_matrix(&self) -> Matrix4x4 {
535 Matrix4x4::look_at(self.get_position(), self.get_target(), self.get_up())
536 }
537
538 pub fn projection_matrix(&self) -> Matrix4x4 {
544 Matrix4x4::perspective(
545 self.get_fov(),
546 self.aspect(),
547 self.get_near(),
548 self.get_far(),
549 )
550 }
551
552 pub fn view_projection_matrix(&self) -> Matrix4x4 {
558 self.projection_matrix().multiply(self.view_matrix())
559 }
560
561 pub fn world_to_screen(&self, world: Vector3D) -> Vector3D {
571 let clip: Vector3D = self.view_projection_matrix().transform_point(world);
572 Vector3D::new(
573 (clip.get_x() + 1.0) * 0.5 * self.get_viewport_width(),
574 (1.0 - clip.get_y()) * 0.5 * self.get_viewport_height(),
575 clip.get_z(),
576 )
577 }
578
579 pub fn is_in_frustum(&self, world: Vector3D) -> bool {
589 let clip: Vector3D = self.view_projection_matrix().transform_point(world);
590 clip.get_x() >= -1.0
591 && clip.get_x() <= 1.0
592 && clip.get_y() >= -1.0
593 && clip.get_y() <= 1.0
594 && clip.get_z() >= -1.0
595 && clip.get_z() <= 1.0
596 }
597
598 pub fn translate(&mut self, offset: Vector3D) {
604 self.set_position(self.get_position() + offset);
605 self.set_target(self.get_target() + offset);
606 }
607
608 pub fn zoom(&mut self, distance: f64) {
614 let direction: Vector3D = self.forward();
615 self.set_position(self.get_position() + direction.scaled(distance));
616 }
617
618 pub fn orbit(&mut self, yaw_delta: f64, pitch_delta: f64) {
625 let offset: Vector3D = self.get_position() - self.get_target();
626 let current_distance: f64 = offset.magnitude();
627 let current_yaw: f64 = offset.get_x().atan2(offset.get_z());
628 let horizontal_dist: f64 =
629 (offset.get_x() * offset.get_x() + offset.get_z() * offset.get_z()).sqrt();
630 let current_pitch: f64 = (offset.get_y() / horizontal_dist.max(EPSILON)).asin();
631 let new_yaw: f64 = current_yaw + yaw_delta;
632 let new_pitch: f64 = Numeric::clamp(
633 current_pitch + pitch_delta,
634 -HALF_PI + EPSILON,
635 HALF_PI - EPSILON,
636 );
637 let cos_pitch: f64 = new_pitch.cos();
638 self.set_position(
639 self.get_target()
640 + Vector3D::new(
641 new_yaw.sin() * cos_pitch * current_distance,
642 new_pitch.sin() * current_distance,
643 new_yaw.cos() * cos_pitch * current_distance,
644 ),
645 );
646 }
647}
648
649impl Default for Camera3D {
651 fn default() -> Camera3D {
652 Camera3D::create(Vector3D::new(0.0, 0.0, 5.0), Vector3D::zero(), 800.0, 600.0)
653 }
654}
655
656impl SsaaCanvas {
658 pub fn from_selector(canvas_selector: &str, width: f64, height: f64) -> Option<SsaaCanvas> {
670 Self::from_selector_with_scale(
671 canvas_selector,
672 width,
673 height,
674 RENDERER_DEFAULT_SSAA_SCALE_FACTOR,
675 )
676 }
677
678 pub fn from_selector_with_scale(
694 canvas_selector: &str,
695 width: f64,
696 height: f64,
697 scale_factor: f64,
698 ) -> Option<SsaaCanvas> {
699 let window_value: Window = window().expect("no global window exists");
700 let document_value: Document = window_value.document().expect("should have a document");
701 let element: Element = document_value
702 .query_selector(canvas_selector)
703 .ok()
704 .flatten()?;
705 let display_canvas: HtmlCanvasElement = element.unchecked_into();
706 display_canvas.set_width(width as u32);
707 display_canvas.set_height(height as u32);
708 let display_context_object: Object = display_canvas
709 .get_context(RENDERER_CONTEXT_TYPE_2D)
710 .ok()
711 .flatten()?;
712 let display_context: CanvasRenderingContext2d = display_context_object.unchecked_into();
713 let offscreen_canvas: HtmlCanvasElement = document_value
714 .create_element(RENDERER_ELEMENT_CANVAS)
715 .ok()?
716 .unchecked_into();
717 let scaled_width: u32 = (width * scale_factor) as u32;
718 let scaled_height: u32 = (height * scale_factor) as u32;
719 offscreen_canvas.set_width(scaled_width);
720 offscreen_canvas.set_height(scaled_height);
721 let offscreen_context_object: Object = offscreen_canvas
722 .get_context(RENDERER_CONTEXT_TYPE_2D)
723 .ok()
724 .flatten()?;
725 let offscreen_context: CanvasRenderingContext2d = offscreen_context_object.unchecked_into();
726 let _ = offscreen_context.scale(scale_factor, scale_factor);
727 let ssaa_canvas: SsaaCanvas = SsaaCanvas::new(
728 display_canvas,
729 display_context,
730 offscreen_canvas,
731 offscreen_context,
732 scale_factor,
733 width,
734 height,
735 );
736 ssaa_canvas.enable_anti_aliasing();
737 Some(ssaa_canvas)
738 }
739
740 pub fn present(&self) {
747 let _ = Reflect::set(
748 &self.display_context,
749 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_ENABLED),
750 &JsValue::from_bool(true),
751 );
752 let _ = Reflect::set(
753 &self.display_context,
754 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_QUALITY),
755 &JsValue::from_str(RENDERER_IMAGE_SMOOTHING_QUALITY_HIGH),
756 );
757 self.display_context
758 .clear_rect(0.0, 0.0, self.width, self.height);
759 let _ = self
760 .display_context
761 .draw_image_with_html_canvas_element_and_dw_and_dh(
762 &self.offscreen_canvas,
763 0.0,
764 0.0,
765 self.width,
766 self.height,
767 );
768 }
769
770 pub fn clear(&self) {
772 self.offscreen_context
773 .clear_rect(0.0, 0.0, self.width, self.height);
774 }
775
776 pub fn clear_with_color(&self, color: &str) {
782 let _ = Reflect::set(
783 &self.offscreen_context,
784 &JsValue::from_str(RENDERER_PROPERTY_FILL_STYLE),
785 &JsValue::from_str(color),
786 );
787 self.offscreen_context
788 .fill_rect(0.0, 0.0, self.width, self.height);
789 }
790
791 pub fn enable_anti_aliasing(&self) {
796 let _ = Reflect::set(
797 &self.display_context,
798 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_ENABLED),
799 &JsValue::from_bool(true),
800 );
801 let _ = Reflect::set(
802 &self.display_context,
803 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_QUALITY),
804 &JsValue::from_str(RENDERER_IMAGE_SMOOTHING_QUALITY_HIGH),
805 );
806 let _ = Reflect::set(
807 &self.offscreen_context,
808 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_ENABLED),
809 &JsValue::from_bool(true),
810 );
811 let _ = Reflect::set(
812 &self.offscreen_context,
813 &JsValue::from_str(RENDERER_PROPERTY_IMAGE_SMOOTHING_QUALITY),
814 &JsValue::from_str(RENDERER_IMAGE_SMOOTHING_QUALITY_HIGH),
815 );
816 }
817}
818
819impl BlendMode {
821 pub fn to_css_string(&self) -> &str {
827 match self {
828 BlendMode::Normal => BLEND_MODE_NORMAL,
829 BlendMode::Multiply => BLEND_MODE_MULTIPLY,
830 BlendMode::Screen => BLEND_MODE_SCREEN,
831 BlendMode::Lighter => BLEND_MODE_LIGHTER,
832 BlendMode::Overlay => BLEND_MODE_OVERLAY,
833 BlendMode::Darken => BLEND_MODE_DARKEN,
834 BlendMode::Lighten => BLEND_MODE_LIGHTEN,
835 BlendMode::ColorDodge => BLEND_MODE_COLOR_DODGE,
836 BlendMode::ColorBurn => BLEND_MODE_COLOR_BURN,
837 BlendMode::HardLight => BLEND_MODE_HARD_LIGHT,
838 BlendMode::SoftLight => BLEND_MODE_SOFT_LIGHT,
839 BlendMode::Difference => BLEND_MODE_DIFFERENCE,
840 BlendMode::Exclusion => BLEND_MODE_EXCLUSION,
841 BlendMode::Hue => BLEND_MODE_HUE,
842 BlendMode::Saturation => BLEND_MODE_SATURATION,
843 BlendMode::Color => BLEND_MODE_COLOR,
844 BlendMode::Luminosity => BLEND_MODE_LUMINOSITY,
845 }
846 }
847}
848
849impl LinearGradient {
851 pub fn create(start: Vector2D, end: Vector2D, stops: Vec<(f64, String)>) -> LinearGradient {
863 LinearGradient::new(start, end, stops)
864 }
865
866 pub fn to_canvas_gradient(&self, context: &CanvasRenderingContext2d) -> Option<CanvasGradient> {
876 let canvas_gradient: CanvasGradient = context.create_linear_gradient(
877 self.get_start().get_x(),
878 self.get_start().get_y(),
879 self.get_end().get_x(),
880 self.get_end().get_y(),
881 );
882 for (position, color) in &self.stops {
883 let _ = canvas_gradient.add_color_stop(*position as f32, color);
884 }
885 Some(canvas_gradient)
886 }
887}
888
889impl RadialGradient {
891 pub fn create(
905 inner_center: Vector2D,
906 inner_radius: f64,
907 outer_center: Vector2D,
908 outer_radius: f64,
909 stops: Vec<(f64, String)>,
910 ) -> RadialGradient {
911 RadialGradient::new(
912 inner_center,
913 inner_radius,
914 outer_center,
915 outer_radius,
916 stops,
917 )
918 }
919
920 pub fn to_canvas_gradient(&self, context: &CanvasRenderingContext2d) -> Option<CanvasGradient> {
930 let canvas_gradient: CanvasGradient = context
931 .create_radial_gradient(
932 self.get_inner_center().get_x(),
933 self.get_inner_center().get_y(),
934 self.get_inner_radius(),
935 self.get_outer_center().get_x(),
936 self.get_outer_center().get_y(),
937 self.get_outer_radius(),
938 )
939 .ok()?;
940 for (position, color) in &self.stops {
941 let _ = canvas_gradient.add_color_stop(*position as f32, color);
942 }
943 Some(canvas_gradient)
944 }
945}
946
947impl ShadowConfig {
949 pub fn create() -> ShadowConfig {
955 ShadowConfig::new(
956 RENDERER_DEFAULT_SHADOW_COLOR.to_string(),
957 RENDERER_DEFAULT_SHADOW_BLUR,
958 0.0,
959 0.0,
960 )
961 }
962}
963
964impl Default for ShadowConfig {
966 fn default() -> ShadowConfig {
967 ShadowConfig::create()
968 }
969}
970
971impl RenderLayer {
973 pub fn create(z_index: i32, visible: bool) -> RenderLayer {
984 RenderLayer::new(z_index, visible)
985 }
986
987 pub fn background() -> RenderLayer {
993 RenderLayer::new(RENDERER_LAYER_BACKGROUND, true)
994 }
995
996 pub fn foreground() -> RenderLayer {
1002 RenderLayer::new(RENDERER_LAYER_FOREGROUND, true)
1003 }
1004
1005 pub fn ui() -> RenderLayer {
1011 RenderLayer::new(RENDERER_LAYER_UI, true)
1012 }
1013}
1014
1015impl CanvasRenderer {
1017 pub fn set_blend_mode(&self, mode: BlendMode) {
1023 let _ = Reflect::set(
1024 self.get_context(),
1025 &JsValue::from_str(RENDERER_PROPERTY_GLOBAL_COMPOSITE_OPERATION),
1026 &JsValue::from_str(mode.to_css_string()),
1027 );
1028 }
1029
1030 pub fn set_shadow(&self, config: &ShadowConfig) {
1036 let _ = Reflect::set(
1037 self.get_context(),
1038 &JsValue::from_str(RENDERER_PROPERTY_SHADOW_COLOR),
1039 &JsValue::from_str(config.get_color().as_str()),
1040 );
1041 let _ = Reflect::set(
1042 self.get_context(),
1043 &JsValue::from_str(RENDERER_PROPERTY_SHADOW_BLUR),
1044 &JsValue::from_f64(config.get_blur()),
1045 );
1046 let _ = Reflect::set(
1047 self.get_context(),
1048 &JsValue::from_str(RENDERER_PROPERTY_SHADOW_OFFSET_X),
1049 &JsValue::from_f64(config.get_offset_x()),
1050 );
1051 let _ = Reflect::set(
1052 self.get_context(),
1053 &JsValue::from_str(RENDERER_PROPERTY_SHADOW_OFFSET_Y),
1054 &JsValue::from_f64(config.get_offset_y()),
1055 );
1056 }
1057
1058 pub fn clear_shadow(&self) {
1060 let _ = Reflect::set(
1061 self.get_context(),
1062 &JsValue::from_str(RENDERER_PROPERTY_SHADOW_COLOR),
1063 &JsValue::from_str("rgba(0, 0, 0, 0)"),
1064 );
1065 let _ = Reflect::set(
1066 self.get_context(),
1067 &JsValue::from_str(RENDERER_PROPERTY_SHADOW_BLUR),
1068 &JsValue::from_f64(0.0),
1069 );
1070 let _ = Reflect::set(
1071 self.get_context(),
1072 &JsValue::from_str(RENDERER_PROPERTY_SHADOW_OFFSET_X),
1073 &JsValue::from_f64(0.0),
1074 );
1075 let _ = Reflect::set(
1076 self.get_context(),
1077 &JsValue::from_str(RENDERER_PROPERTY_SHADOW_OFFSET_Y),
1078 &JsValue::from_f64(0.0),
1079 );
1080 }
1081
1082 pub fn set_linear_gradient_fill(&self, gradient: &LinearGradient) {
1088 if let Some(canvas_gradient) = gradient.to_canvas_gradient(self.get_context()) {
1089 let _ = Reflect::set(
1090 self.get_context(),
1091 &JsValue::from_str(RENDERER_PROPERTY_FILL_STYLE),
1092 &canvas_gradient,
1093 );
1094 }
1095 }
1096
1097 pub fn set_radial_gradient_fill(&self, gradient: &RadialGradient) {
1103 if let Some(canvas_gradient) = gradient.to_canvas_gradient(self.get_context()) {
1104 let _ = Reflect::set(
1105 self.get_context(),
1106 &JsValue::from_str(RENDERER_PROPERTY_FILL_STYLE),
1107 &canvas_gradient,
1108 );
1109 }
1110 }
1111
1112 pub fn set_linear_gradient_stroke(&self, gradient: &LinearGradient) {
1118 if let Some(canvas_gradient) = gradient.to_canvas_gradient(self.get_context()) {
1119 let _ = Reflect::set(
1120 self.get_context(),
1121 &JsValue::from_str(RENDERER_PROPERTY_STROKE_STYLE),
1122 &canvas_gradient,
1123 );
1124 }
1125 }
1126
1127 pub fn set_radial_gradient_stroke(&self, gradient: &RadialGradient) {
1133 if let Some(canvas_gradient) = gradient.to_canvas_gradient(self.get_context()) {
1134 let _ = Reflect::set(
1135 self.get_context(),
1136 &JsValue::from_str(RENDERER_PROPERTY_STROKE_STYLE),
1137 &canvas_gradient,
1138 );
1139 }
1140 }
1141}
1142
1143impl RenderBackend for CanvasRenderer {
1146 fn clear(&self) {
1147 self.clear();
1148 }
1149
1150 fn clear_with_color(&self, color: &str) {
1151 self.clear_with_color(color);
1152 }
1153
1154 fn save(&self) {
1155 self.save();
1156 }
1157
1158 fn restore(&self) {
1159 self.restore();
1160 }
1161
1162 fn set_fill_color(&self, color: &str) {
1163 self.set_fill_color(color);
1164 }
1165
1166 fn set_stroke_color(&self, color: &str) {
1167 self.set_stroke_color(color);
1168 }
1169
1170 fn set_line_width(&self, width: f64) {
1171 self.set_line_width(width);
1172 }
1173
1174 fn set_global_alpha(&self, alpha: f64) {
1175 self.set_global_alpha(alpha);
1176 }
1177
1178 fn set_blend_mode(&self, mode: BlendMode) {
1179 self.set_blend_mode(mode);
1180 }
1181
1182 fn set_shadow(&self, config: &ShadowConfig) {
1183 self.set_shadow(config);
1184 }
1185
1186 fn clear_shadow(&self) {
1187 self.clear_shadow();
1188 }
1189
1190 fn fill_rect(&self, position: Vector2D, width: f64, height: f64) {
1191 self.fill_rect(position, width, height);
1192 }
1193
1194 fn stroke_rect(&self, position: Vector2D, width: f64, height: f64) {
1195 self.stroke_rect(position, width, height);
1196 }
1197
1198 fn fill_circle(&self, center: Vector2D, radius: f64) {
1199 self.fill_circle(center, radius);
1200 }
1201
1202 fn stroke_circle(&self, center: Vector2D, radius: f64) {
1203 self.stroke_circle(center, radius);
1204 }
1205
1206 fn draw_line(&self, start: Vector2D, end: Vector2D) {
1207 self.draw_line(start, end);
1208 }
1209
1210 fn fill_text(&self, text: &str, position: Vector2D) {
1211 self.fill_text(text, position);
1212 }
1213
1214 fn set_font(&self, font: &str) {
1215 self.set_font(font);
1216 }
1217
1218 fn draw_image(&self, image: &HtmlImageElement, position: Vector2D, width: f64, height: f64) {
1219 self.draw_image(image, position, width, height);
1220 }
1221
1222 fn set_linear_gradient_fill(&self, gradient: &LinearGradient) {
1223 self.set_linear_gradient_fill(gradient);
1224 }
1225
1226 fn set_radial_gradient_fill(&self, gradient: &RadialGradient) {
1227 self.set_radial_gradient_fill(gradient);
1228 }
1229}