Bezier-rs: Update interactive demo site UI/UX (#1085)

* wip - change demo iframe styling

* fix typo

* change tVariant select from radio buttons to dropdown

* Added iframe styling

* fix linting errors

* Integrated tvariant picker as input options

* Updated points in demos

* Lint

* Clean up CSS

---------

Co-authored-by: Thomas Cheng <contact.chengthomas@gmail.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Rob Nadal
2023-03-21 01:23:02 -04:00
committed by Keavon Chambers
co-authored by Thomas Cheng Keavon Chambers
parent bfbabbc4dc
commit 834cb1a227
15 changed files with 402 additions and 297 deletions
@@ -1,6 +1,6 @@
import { WasmBezier } from "@/../wasm/pkg";
import { tSliderOptions, errorOptions, minimumSeparationOptions } from "@/utils/options";
import { TVariant, BezierDemoOptions, WasmBezierInstance, BezierCallback } from "@/utils/types";
import { tSliderOptions, bezierTValueVariantOptions, errorOptions, minimumSeparationOptions } from "@/utils/options";
import { BezierDemoOptions, WasmBezierInstance, BezierCallback, InputOption, BEZIER_T_VALUE_VARIANTS } from "@/utils/types";
const bezierFeatures = {
constructor: {
@@ -26,7 +26,7 @@ const bezierFeatures = {
[120, 70],
[160, 170],
],
sliderOptions: [
inputOptions: [
{
min: 0.01,
max: 0.99,
@@ -42,7 +42,7 @@ const bezierFeatures = {
[120, 70],
[160, 170],
],
sliderOptions: [
inputOptions: [
{
min: 0.01,
max: 0.99,
@@ -67,20 +67,19 @@ const bezierFeatures = {
},
evaluate: {
name: "Evaluate",
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => bezier.evaluate(options.t, tVariant),
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined): string => bezier.evaluate(options.t, BEZIER_T_VALUE_VARIANTS[options.TVariant]),
demoOptions: {
Quadratic: {
sliderOptions: [tSliderOptions],
inputOptions: [bezierTValueVariantOptions, tSliderOptions],
},
},
chooseTVariant: true,
},
"lookup-table": {
name: "Lookup Table",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.compute_lookup_table(options.steps),
demoOptions: {
Quadratic: {
sliderOptions: [
inputOptions: [
{
min: 2,
max: 15,
@@ -118,53 +117,53 @@ const bezierFeatures = {
},
tangent: {
name: "Tangent",
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => bezier.tangent(options.t, tVariant),
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined): string => bezier.tangent(options.t, BEZIER_T_VALUE_VARIANTS[options.TVariant]),
demoOptions: {
Quadratic: {
sliderOptions: [tSliderOptions],
inputOptions: [bezierTValueVariantOptions, tSliderOptions],
},
},
chooseTVariant: true,
},
normal: {
name: "Normal",
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => bezier.normal(options.t, tVariant),
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined): string => bezier.normal(options.t, BEZIER_T_VALUE_VARIANTS[options.TVariant]),
demoOptions: {
Quadratic: {
sliderOptions: [tSliderOptions],
inputOptions: [bezierTValueVariantOptions, tSliderOptions],
},
},
chooseTVariant: true,
},
curvature: {
name: "Curvature",
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => bezier.curvature(options.t, tVariant),
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined): string => bezier.curvature(options.t, BEZIER_T_VALUE_VARIANTS[options.TVariant]),
demoOptions: {
Linear: {
disabled: true,
},
Quadratic: {
sliderOptions: [tSliderOptions],
inputOptions: [bezierTValueVariantOptions, tSliderOptions],
},
Cubic: {
inputOptions: [bezierTValueVariantOptions, { ...tSliderOptions, default: 0.7 }],
},
},
chooseTVariant: true,
},
split: {
name: "Split",
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => bezier.split(options.t, tVariant),
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined): string => bezier.split(options.t, BEZIER_T_VALUE_VARIANTS[options.TVariant]),
demoOptions: {
Quadratic: {
sliderOptions: [tSliderOptions],
inputOptions: [bezierTValueVariantOptions, tSliderOptions],
},
},
chooseTVariant: true,
},
trim: {
name: "Trim",
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => bezier.trim(options.t1, options.t2, tVariant),
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined): string => bezier.trim(options.t1, options.t2, BEZIER_T_VALUE_VARIANTS[options.TVariant]),
demoOptions: {
Quadratic: {
sliderOptions: [
inputOptions: [
bezierTValueVariantOptions,
{
variable: "t1",
min: 0,
@@ -182,7 +181,6 @@ const bezierFeatures = {
],
},
},
chooseTVariant: true,
},
project: {
name: "Project",
@@ -194,6 +192,9 @@ const bezierFeatures = {
name: "Local Extrema",
callback: (bezier: WasmBezierInstance, _: Record<string, number>): string => bezier.local_extrema(),
demoOptions: {
Linear: {
disabled: true,
},
Quadratic: {
customPoints: [
[40, 40],
@@ -236,7 +237,7 @@ const bezierFeatures = {
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.offset(options.distance),
demoOptions: {
Quadratic: {
sliderOptions: [
inputOptions: [
{
variable: "distance",
min: -30,
@@ -253,7 +254,7 @@ const bezierFeatures = {
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.outline(options.distance),
demoOptions: {
Quadratic: {
sliderOptions: [
inputOptions: [
{
variable: "distance",
min: 0,
@@ -270,7 +271,7 @@ const bezierFeatures = {
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.graduated_outline(options.start_distance, options.end_distance),
demoOptions: {
Quadratic: {
sliderOptions: [
inputOptions: [
{
variable: "start_distance",
min: 0,
@@ -302,7 +303,7 @@ const bezierFeatures = {
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.skewed_outline(options.distance1, options.distance2, options.distance3, options.distance4),
demoOptions: {
Quadratic: {
sliderOptions: [
inputOptions: [
{
variable: "distance1",
min: 0,
@@ -338,15 +339,13 @@ const bezierFeatures = {
arcs: {
name: "Arcs",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.arcs(options.error, options.max_iterations, options.strategy),
demoOptions: ((): Omit<BezierDemoOptions, "Linear"> => {
const sliderOptions = [
demoOptions: ((): BezierDemoOptions => {
const inputOptions: InputOption[] = [
{
variable: "strategy",
min: 0,
max: 2,
step: 1,
default: 0,
unit: [": Automatic", ": FavorLargerArcs", ": FavorCorrectness"],
inputType: "dropdown",
options: ["Automatic", "FavorLargerArcs", "FavorCorrectness"],
},
{
variable: "error",
@@ -365,13 +364,16 @@ const bezierFeatures = {
];
return {
Linear: {
disabled: true,
},
Quadratic: {
customPoints: [
[50, 50],
[85, 65],
[100, 100],
[70, 40],
[180, 50],
[160, 150],
],
sliderOptions,
inputOptions,
disabled: false,
},
Cubic: {
@@ -381,7 +383,7 @@ const bezierFeatures = {
[30, 90],
[180, 160],
],
sliderOptions,
inputOptions,
disabled: false,
},
};
@@ -391,8 +393,8 @@ const bezierFeatures = {
name: "Intersect (Line Segment)",
callback: (bezier: WasmBezierInstance): string => {
const line = [
[150, 150],
[20, 20],
[45, 30],
[195, 160],
];
return bezier.intersect_line_segment(line);
},
@@ -401,15 +403,15 @@ const bezierFeatures = {
name: "Intersect (Quadratic)",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => {
const quadratic = [
[20, 80],
[180, 10],
[90, 120],
[45, 80],
[205, 10],
[115, 120],
];
return bezier.intersect_quadratic_segment(quadratic, options.error, options.minimum_separation);
},
demoOptions: {
Quadratic: {
sliderOptions: [errorOptions, minimumSeparationOptions],
inputOptions: [errorOptions, minimumSeparationOptions],
},
},
},
@@ -417,16 +419,16 @@ const bezierFeatures = {
name: "Intersect (Cubic)",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => {
const cubic = [
[40, 20],
[100, 40],
[40, 120],
[175, 140],
[65, 20],
[125, 40],
[65, 120],
[200, 140],
];
return bezier.intersect_cubic_segment(cubic, options.error, options.minimum_separation);
},
demoOptions: {
Quadratic: {
sliderOptions: [errorOptions, minimumSeparationOptions],
inputOptions: [errorOptions, minimumSeparationOptions],
},
},
},
@@ -434,10 +436,14 @@ const bezierFeatures = {
name: "Intersect (Self)",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.intersect_self(options.error),
demoOptions: {
Linear: {
disabled: true,
},
Quadratic: {
sliderOptions: [errorOptions],
disabled: true,
},
Cubic: {
inputOptions: [errorOptions],
customPoints: [
[160, 180],
[170, 10],
@@ -451,8 +457,8 @@ const bezierFeatures = {
name: "Intersect (Rectangle)",
callback: (bezier: WasmBezierInstance): string =>
bezier.intersect_rectangle([
[50, 50],
[150, 150],
[75, 50],
[175, 150],
]),
},
rotate: {
@@ -460,7 +466,7 @@ const bezierFeatures = {
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.rotate(options.angle * Math.PI, 100, 100),
demoOptions: {
Quadratic: {
sliderOptions: [
inputOptions: [
{
variable: "angle",
min: 0,
@@ -475,13 +481,12 @@ const bezierFeatures = {
},
"de-casteljau-points": {
name: "De Casteljau Points",
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => bezier.de_casteljau_points(options.t, tVariant),
callback: (bezier: WasmBezierInstance, options: Record<string, number>, _: undefined): string => bezier.de_casteljau_points(options.t, BEZIER_T_VALUE_VARIANTS[options.TVariant]),
demoOptions: {
Quadratic: {
sliderOptions: [tSliderOptions],
inputOptions: [bezierTValueVariantOptions, tSliderOptions],
},
},
chooseTVariant: true,
},
join: {
name: "Join",
@@ -490,21 +495,21 @@ const bezierFeatures = {
let examplePoints = [];
if (points.length === 2) {
examplePoints = [
[120, 155],
[40, 155],
[145, 155],
[65, 155],
];
} else if (points.length === 3) {
examplePoints = [
[40, 150],
[95, 195],
[155, 145],
[65, 150],
[120, 195],
[190, 145],
];
} else {
examplePoints = [
[140, 150],
[85, 110],
[65, 180],
[30, 140],
[165, 150],
[110, 110],
[90, 180],
[55, 140],
];
}
return bezier.join(examplePoints);
@@ -512,23 +517,23 @@ const bezierFeatures = {
demoOptions: {
Linear: {
customPoints: [
[45, 40],
[130, 90],
[70, 40],
[155, 90],
],
},
Quadratic: {
customPoints: [
[153, 40],
[40, 20],
[75, 85],
[185, 40],
[65, 20],
[100, 85],
],
},
Cubic: {
customPoints: [
[20, 80],
[40, 20],
[90, 100],
[130, 55],
[45, 80],
[65, 20],
[115, 100],
[155, 55],
],
},
},
@@ -541,6 +546,5 @@ export type BezierFeatureOptions = {
callback: BezierCallback;
demoOptions?: Partial<BezierDemoOptions>;
triggerOnMouseMove?: boolean;
chooseTVariant?: boolean;
};
export default bezierFeatures as Record<BezierFeatureKey, BezierFeatureOptions>;
@@ -1,5 +1,5 @@
import { tSliderOptions, intersectionErrorOptions, minimumSeparationOptions } from "@/utils/options";
import { TVariant, SliderOption, SubpathCallback, WasmSubpathInstance } from "@/utils/types";
import { tSliderOptions, subpathTValueVariantOptions, intersectionErrorOptions, minimumSeparationOptions } from "@/utils/options";
import { InputOption, SubpathCallback, WasmSubpathInstance, SUBPATH_T_VALUE_VARIANTS } from "@/utils/types";
const subpathFeatures = {
constructor: {
@@ -8,9 +8,8 @@ const subpathFeatures = {
},
insert: {
name: "Insert",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => subpath.insert(options.t, tVariant),
sliderOptions: [tSliderOptions],
chooseTVariant: true,
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.insert(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),
inputOptions: [subpathTValueVariantOptions, tSliderOptions],
},
length: {
name: "Length",
@@ -18,9 +17,8 @@ const subpathFeatures = {
},
evaluate: {
name: "Evaluate",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => subpath.evaluate(options.t, tVariant),
sliderOptions: [tSliderOptions],
chooseTVariant: true,
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.evaluate(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),
inputOptions: [subpathTValueVariantOptions, tSliderOptions],
},
project: {
name: "Project",
@@ -30,15 +28,13 @@ const subpathFeatures = {
},
tangent: {
name: "Tangent",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => subpath.tangent(options.t, tVariant),
sliderOptions: [tSliderOptions],
chooseTVariant: true,
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.tangent(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),
inputOptions: [subpathTValueVariantOptions, tSliderOptions],
},
normal: {
name: "Normal",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => subpath.normal(options.t, tVariant),
sliderOptions: [tSliderOptions],
chooseTVariant: true,
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.normal(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),
inputOptions: [subpathTValueVariantOptions, tSliderOptions],
},
"local-extrema": {
name: "Local Extrema",
@@ -57,67 +53,62 @@ const subpathFeatures = {
callback: (subpath: WasmSubpathInstance, options: Record<string, number>): string =>
subpath.intersect_line_segment(
[
[150, 150],
[20, 20],
[80, 30],
[210, 150],
],
options.error,
options.minimum_seperation
options.minimum_separation
),
sliderOptions: [intersectionErrorOptions, minimumSeparationOptions],
inputOptions: [intersectionErrorOptions, minimumSeparationOptions],
},
"intersect-quadratic": {
name: "Intersect (Quadratic Segment)",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>): string =>
subpath.intersect_quadratic_segment(
[
[20, 80],
[180, 10],
[90, 120],
[25, 50],
[205, 10],
[135, 180],
],
options.error,
options.minimum_seperation
options.minimum_separation
),
sliderOptions: [intersectionErrorOptions, minimumSeparationOptions],
inputOptions: [intersectionErrorOptions, minimumSeparationOptions],
},
"intersect-cubic": {
name: "Intersect (Cubic Segment)",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>): string =>
subpath.intersect_cubic_segment(
[
[40, 20],
[100, 40],
[40, 120],
[175, 140],
[65, 20],
[125, 40],
[65, 120],
[200, 140],
],
options.error,
options.minimum_seperation
options.minimum_separation
),
sliderOptions: [intersectionErrorOptions, minimumSeparationOptions],
inputOptions: [intersectionErrorOptions, minimumSeparationOptions],
},
"self-intersect": {
name: "Self Intersect",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>): string => subpath.self_intersections(options.error, options.minimum_seperation),
sliderOptions: [intersectionErrorOptions, minimumSeparationOptions],
callback: (subpath: WasmSubpathInstance, options: Record<string, number>): string => subpath.self_intersections(options.error, options.minimum_separation),
inputOptions: [intersectionErrorOptions, minimumSeparationOptions],
},
split: {
name: "Split",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => subpath.split(options.t, tVariant),
sliderOptions: [tSliderOptions],
chooseTVariant: true,
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.split(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),
inputOptions: [subpathTValueVariantOptions, tSliderOptions],
},
trim: {
name: "Trim",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined, tVariant: TVariant): string => subpath.trim(options.tVariant1, options.tVariant2, tVariant),
sliderOptions: [
{ ...tSliderOptions, default: 0.2, variable: "tVariant1" },
{ ...tSliderOptions, variable: "tVariant2" },
],
chooseTVariant: true,
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.trim(options.t1, options.t2, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),
inputOptions: [subpathTValueVariantOptions, { ...tSliderOptions, default: 0.2, variable: "t1" }, { ...tSliderOptions, variable: "t2" }],
},
offset: {
name: "Offset",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>): string => subpath.offset(options.distance),
sliderOptions: [
inputOptions: [
{
variable: "distance",
min: -25,
@@ -130,7 +121,7 @@ const subpathFeatures = {
outline: {
name: "Outline",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>): string => subpath.outline(options.distance),
sliderOptions: [
inputOptions: [
{
variable: "distance",
min: 0,
@@ -146,8 +137,7 @@ export type SubpathFeatureKey = keyof typeof subpathFeatures;
export type SubpathFeatureOptions = {
name: string;
callback: SubpathCallback;
sliderOptions?: SliderOption[];
inputOptions?: InputOption[];
triggerOnMouseMove?: boolean;
chooseTVariant?: boolean;
};
export default subpathFeatures as Record<SubpathFeatureKey, SubpathFeatureOptions>;