From e9cd792635f4149cdea55488f267860dd2f052b6 Mon Sep 17 00:00:00 2001 From: Hannah Li Date: Mon, 26 Sep 2022 19:14:27 -0700 Subject: [PATCH] Bezier-rs: Convert from canvas to svg for constructors (#776) * Convert constructor to use svg * Convert the through_points functions to svg Co-authored-by: Keavon Chambers --- libraries/bezier-rs/src/svg.rs | 8 +- website/other/bezier-rs-demos/src/App.vue | 70 +++++++----- .../src/components/BezierDrawing.ts | 19 +--- .../src/components/BezierExample.vue | 105 ++++++++++++++++++ .../src/components/BezierExamplePane.vue | 85 ++++++++++++++ .../src/components/Example.vue | 4 +- .../bezier-rs-demos/src/utils/helpers.ts | 27 +++++ .../other/bezier-rs-demos/src/utils/types.ts | 11 +- .../other/bezier-rs-demos/wasm/src/bezier.rs | 34 ++++-- .../bezier-rs-demos/wasm/src/svg_drawing.rs | 2 + 10 files changed, 308 insertions(+), 57 deletions(-) create mode 100644 website/other/bezier-rs-demos/src/components/BezierExample.vue create mode 100644 website/other/bezier-rs-demos/src/components/BezierExamplePane.vue create mode 100644 website/other/bezier-rs-demos/src/utils/helpers.ts diff --git a/libraries/bezier-rs/src/svg.rs b/libraries/bezier-rs/src/svg.rs index d7352c01..fb175083 100644 --- a/libraries/bezier-rs/src/svg.rs +++ b/libraries/bezier-rs/src/svg.rs @@ -28,12 +28,12 @@ pub struct ToSVGOptions { impl ToSVGOptions { /// Combine and format curve styling options for an SVG path. - pub(crate) fn formatted_curve_arguments(&self) -> String { + pub fn formatted_curve_arguments(&self) -> String { format!(r#"stroke="{}" stroke-width="{}" fill="none""#, self.curve_stroke_color, self.curve_stroke_width) } /// Combine and format anchor styling options an SVG circle. - pub(crate) fn formatted_anchor_arguments(&self) -> String { + pub fn formatted_anchor_arguments(&self) -> String { format!( r#"r="{}", stroke="{}" stroke-width="{}" fill="{}""#, self.anchor_radius, self.anchor_stroke_color, self.anchor_stroke_width, self.anchor_fill @@ -41,7 +41,7 @@ impl ToSVGOptions { } /// Combine and format handle point styling options for an SVG circle. - pub(crate) fn formatted_handle_point_arguments(&self) -> String { + pub fn formatted_handle_point_arguments(&self) -> String { format!( r#"r="{}", stroke="{}" stroke-width="{}" fill="{}""#, self.handle_point_radius, self.handle_point_stroke_color, self.handle_point_stroke_width, self.handle_point_fill @@ -49,7 +49,7 @@ impl ToSVGOptions { } /// Combine and format handle line styling options an SVG path. - pub(crate) fn formatted_handle_line_arguments(&self) -> String { + pub fn formatted_handle_line_arguments(&self) -> String { format!(r#"stroke="{}" stroke-width="{}" fill="none""#, self.handle_line_stroke_color, self.handle_line_stroke_width) } } diff --git a/website/other/bezier-rs-demos/src/App.vue b/website/other/bezier-rs-demos/src/App.vue index 88d07237..1b9f4444 100644 --- a/website/other/bezier-rs-demos/src/App.vue +++ b/website/other/bezier-rs-demos/src/App.vue @@ -4,15 +4,16 @@

This is the interactive documentation for the bezier-rs library. Click and drag on the endpoints of the example curves to visualize the various Bezier utilities and functions.

Beziers

+ +
+

Subpaths

@@ -25,9 +26,11 @@ + + diff --git a/website/other/bezier-rs-demos/src/components/BezierExamplePane.vue b/website/other/bezier-rs-demos/src/components/BezierExamplePane.vue new file mode 100644 index 00000000..ac92434a --- /dev/null +++ b/website/other/bezier-rs-demos/src/components/BezierExamplePane.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/website/other/bezier-rs-demos/src/components/Example.vue b/website/other/bezier-rs-demos/src/components/Example.vue index b5411bca..92e1ac69 100644 --- a/website/other/bezier-rs-demos/src/components/Example.vue +++ b/website/other/bezier-rs-demos/src/components/Example.vue @@ -9,7 +9,7 @@ import { defineComponent, PropType } from "vue"; import BezierDrawing from "@/components/BezierDrawing"; -import { BezierCallback, WasmBezierInstance } from "@/utils/types"; +import { Callback, WasmBezierInstance } from "@/utils/types"; export default defineComponent({ props: { @@ -19,7 +19,7 @@ export default defineComponent({ required: true, }, callback: { - type: Function as PropType, + type: Function as PropType, required: true, }, options: { diff --git a/website/other/bezier-rs-demos/src/utils/helpers.ts b/website/other/bezier-rs-demos/src/utils/helpers.ts new file mode 100644 index 00000000..b3c65460 --- /dev/null +++ b/website/other/bezier-rs-demos/src/utils/helpers.ts @@ -0,0 +1,27 @@ +import { BezierCurveType, WasmBezierConstructorKey } from "@/utils/types"; + +export const getCurveType = (numPoints: number): BezierCurveType => { + switch (numPoints) { + case 2: + return BezierCurveType.Linear; + case 3: + return BezierCurveType.Quadratic; + case 4: + return BezierCurveType.Cubic; + default: + throw new Error("Invalid number of points for a bezier"); + } +}; + +export const getConstructorKey = (bezierCurveType: BezierCurveType): WasmBezierConstructorKey => { + switch (bezierCurveType) { + case BezierCurveType.Linear: + return "new_linear"; + case BezierCurveType.Quadratic: + return "new_quadratic"; + case BezierCurveType.Cubic: + return "new_cubic"; + default: + throw new Error("Invalid value for a BezierCurveType"); + } +}; diff --git a/website/other/bezier-rs-demos/src/utils/types.ts b/website/other/bezier-rs-demos/src/utils/types.ts index e06ceb23..87d36c81 100644 --- a/website/other/bezier-rs-demos/src/utils/types.ts +++ b/website/other/bezier-rs-demos/src/utils/types.ts @@ -14,9 +14,18 @@ export enum BezierCurveType { Cubic = "Cubic", } -export type BezierCallback = (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record, mouseLocation?: Point) => void; +export type Callback = (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record, mouseLocation?: Point) => void; +export type BezierCallback = (bezier: WasmBezierInstance, options: Record) => string; export type SubpathCallback = (subpath: WasmSubpathInstance) => string; +export type ExampleOptions = { + [key in BezierCurveType]: { + disabled: boolean; + sliderOptions: SliderOption[]; + customPoints: number[][]; + }; +}; + export type SliderOption = { min: number; max: number; diff --git a/website/other/bezier-rs-demos/wasm/src/bezier.rs b/website/other/bezier-rs-demos/wasm/src/bezier.rs index 9d4deaf9..88d524e0 100644 --- a/website/other/bezier-rs-demos/wasm/src/bezier.rs +++ b/website/other/bezier-rs-demos/wasm/src/bezier.rs @@ -1,5 +1,5 @@ use crate::svg_drawing::*; -use bezier_rs::{ArcStrategy, ArcsOptions, Bezier, ProjectionOptions, ToSVGOptions}; +use bezier_rs::{ArcStrategy, ArcsOptions, Bezier, ProjectionOptions}; use glam::DVec2; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; @@ -55,6 +55,10 @@ fn convert_wasm_maximize_arcs(wasm_enum_value: WasmMaximizeArcs) -> ArcStrategy } } +fn wrap_svg_tag(contents: String) -> String { + format!("{}{}{}", SVG_OPEN_TAG, contents, SVG_CLOSE_TAG) +} + #[wasm_bindgen] impl WasmBezier { /// Expect js_points to be a list of 2 pairs. @@ -75,14 +79,30 @@ impl WasmBezier { WasmBezier(Bezier::from_cubic_dvec2(points[0], points[1], points[2], points[3])) } - pub fn quadratic_through_points(js_points: &JsValue, t: f64) -> WasmBezier { - let points: [DVec2; 3] = js_points.into_serde().unwrap(); - WasmBezier(Bezier::quadratic_through_points(points[0], points[1], points[2], Some(t))) + fn draw_bezier_through_points(bezier: Bezier, through_point: DVec2) -> String { + let mut bezier_string = String::new(); + bezier.to_svg( + &mut bezier_string, + CURVE_ATTRIBUTES.to_string(), + ANCHOR_ATTRIBUTES.to_string(), + HANDLE_ATTRIBUTES.to_string().replace(GRAY, RED), + HANDLE_LINE_ATTRIBUTES.to_string().replace(GRAY, RED), + ); + let through_point_circle = format!(r#""#, through_point.x, through_point.y, ANCHOR_ATTRIBUTES.to_string()); + + wrap_svg_tag(format!("{bezier_string}{through_point_circle}")) } - pub fn cubic_through_points(js_points: &JsValue, t: f64, midpoint_separation: f64) -> WasmBezier { + pub fn quadratic_through_points(js_points: &JsValue, t: f64) -> String { let points: [DVec2; 3] = js_points.into_serde().unwrap(); - WasmBezier(Bezier::cubic_through_points(points[0], points[1], points[2], Some(t), Some(midpoint_separation))) + let bezier = Bezier::quadratic_through_points(points[0], points[1], points[2], Some(t)); + WasmBezier::draw_bezier_through_points(bezier, points[1]) + } + + pub fn cubic_through_points(js_points: &JsValue, t: f64, midpoint_separation: f64) -> String { + let points: [DVec2; 3] = js_points.into_serde().unwrap(); + let bezier = Bezier::cubic_through_points(points[0], points[1], points[2], Some(t), Some(midpoint_separation)); + WasmBezier::draw_bezier_through_points(bezier, points[1]) } pub fn set_start(&mut self, x: f64, y: f64) { @@ -116,7 +136,7 @@ impl WasmBezier { HANDLE_ATTRIBUTES.to_string(), HANDLE_LINE_ATTRIBUTES.to_string(), ); - format!("{}{}{}", SVG_OPEN_TAG, bezier, SVG_CLOSE_TAG) + wrap_svg_tag(bezier) } pub fn length(&self) -> f64 { diff --git a/website/other/bezier-rs-demos/wasm/src/svg_drawing.rs b/website/other/bezier-rs-demos/wasm/src/svg_drawing.rs index f65b0de0..83e761a6 100644 --- a/website/other/bezier-rs-demos/wasm/src/svg_drawing.rs +++ b/website/other/bezier-rs-demos/wasm/src/svg_drawing.rs @@ -4,6 +4,8 @@ pub const SVG_CLOSE_TAG: &str = ""; // Stylistic constants pub const BLACK: &str = "black"; +pub const GRAY: &str = "gray"; +pub const RED: &str = "red"; // Default attributes pub const CURVE_ATTRIBUTES: &str = "stroke=\"black\" stroke-width=\"2\" fill=\"none\"";