mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-05 06:28:11 +08:00
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:
committed by
Keavon Chambers
co-authored by
Thomas Cheng
Keavon Chambers
parent
bfbabbc4dc
commit
834cb1a227
@@ -1,3 +1,5 @@
|
||||
import { BEZIER_T_VALUE_VARIANTS, SUBPATH_T_VALUE_VARIANTS } from "@/utils/types";
|
||||
|
||||
export const tSliderOptions = {
|
||||
min: 0,
|
||||
max: 1,
|
||||
@@ -15,7 +17,7 @@ export const errorOptions = {
|
||||
};
|
||||
|
||||
export const minimumSeparationOptions = {
|
||||
variable: "minimum_seperation",
|
||||
variable: "minimum_separation",
|
||||
min: 0.001,
|
||||
max: 0.25,
|
||||
step: 0.001,
|
||||
@@ -29,3 +31,17 @@ export const intersectionErrorOptions = {
|
||||
step: 0.0025,
|
||||
default: 0.02,
|
||||
};
|
||||
|
||||
export const bezierTValueVariantOptions = {
|
||||
variable: "TVariant",
|
||||
default: 0,
|
||||
inputType: "dropdown",
|
||||
options: BEZIER_T_VALUE_VARIANTS,
|
||||
};
|
||||
|
||||
export const subpathTValueVariantOptions = {
|
||||
variable: "TVariant",
|
||||
default: 0,
|
||||
inputType: "dropdown",
|
||||
options: SUBPATH_T_VALUE_VARIANTS,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TVariant, Demo, DemoPane, SliderOption } from "@/utils/types";
|
||||
import { Demo, DemoPane, InputOption } from "@/utils/types";
|
||||
|
||||
export function renderDemo(demo: Demo): void {
|
||||
const header = document.createElement("h4");
|
||||
@@ -14,28 +14,72 @@ export function renderDemo(demo: Demo): void {
|
||||
demo.append(header);
|
||||
demo.append(figure);
|
||||
|
||||
demo.sliderOptions.forEach((sliderOption: SliderOption) => {
|
||||
const sliderLabel = document.createElement("div");
|
||||
const sliderData = demo.sliderData[sliderOption.variable];
|
||||
const sliderUnit = demo.getSliderUnit(sliderData, sliderOption.variable);
|
||||
sliderLabel.className = "slider-label";
|
||||
sliderLabel.innerText = `${sliderOption.variable} = ${sliderData}${sliderUnit}`;
|
||||
demo.append(sliderLabel);
|
||||
const parentSliderContainer = document.createElement("div");
|
||||
parentSliderContainer.className = "parent-slider-container";
|
||||
|
||||
const sliderInput = document.createElement("input");
|
||||
sliderInput.className = "slider-input";
|
||||
sliderInput.type = "range";
|
||||
sliderInput.max = String(sliderOption.max);
|
||||
sliderInput.min = String(sliderOption.min);
|
||||
sliderInput.step = String(sliderOption.step);
|
||||
sliderInput.value = String(sliderOption.default);
|
||||
sliderInput.addEventListener("input", (event: Event): void => {
|
||||
demo.sliderData[sliderOption.variable] = Number((event.target as HTMLInputElement).value);
|
||||
sliderLabel.innerText = `${sliderOption.variable} = ${demo.sliderData[sliderOption.variable]}${sliderUnit}`;
|
||||
demo.drawDemo(figure);
|
||||
});
|
||||
demo.append(sliderInput);
|
||||
demo.inputOptions.forEach((inputOption: InputOption) => {
|
||||
const isDropdown = inputOption.inputType === "dropdown";
|
||||
|
||||
const sliderContainer = document.createElement("div");
|
||||
sliderContainer.className = isDropdown ? "select-container" : "slider-container";
|
||||
|
||||
const sliderLabel = document.createElement("div");
|
||||
const sliderData = demo.sliderData[inputOption.variable];
|
||||
const sliderUnit = demo.getSliderUnit(sliderData, inputOption.variable);
|
||||
sliderLabel.className = "slider-label";
|
||||
sliderLabel.innerText = `${inputOption.variable}: ${isDropdown ? "" : sliderData}${sliderUnit}`;
|
||||
sliderContainer.appendChild(sliderLabel);
|
||||
|
||||
if (isDropdown) {
|
||||
const selectInput = document.createElement("select");
|
||||
selectInput.className = "select-input";
|
||||
selectInput.value = String(inputOption.default);
|
||||
inputOption.options?.forEach((value, idx) => {
|
||||
const id = `${idx}-${value}`;
|
||||
const option = document.createElement("option");
|
||||
option.value = String(idx);
|
||||
option.id = id;
|
||||
option.text = value;
|
||||
selectInput.append(option);
|
||||
});
|
||||
|
||||
selectInput.addEventListener("change", (event: Event): void => {
|
||||
demo.sliderData[inputOption.variable] = Number((event.target as HTMLInputElement).value);
|
||||
demo.drawDemo(figure);
|
||||
});
|
||||
sliderContainer.appendChild(selectInput);
|
||||
} else {
|
||||
const sliderInput = document.createElement("input");
|
||||
sliderInput.className = "slider-input";
|
||||
sliderInput.type = "range";
|
||||
sliderInput.max = String(inputOption.max);
|
||||
sliderInput.min = String(inputOption.min);
|
||||
sliderInput.step = String(inputOption.step);
|
||||
sliderInput.value = String(inputOption.default);
|
||||
const range = Number(inputOption.max) - Number(inputOption.min);
|
||||
|
||||
const ratio = (Number(inputOption.default) - Number(inputOption.min)) / range;
|
||||
sliderInput.style.setProperty("--range-ratio", String(ratio));
|
||||
|
||||
sliderInput.addEventListener("input", (event: Event): void => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
demo.sliderData[inputOption.variable] = Number(target.value);
|
||||
const data = demo.sliderData[inputOption.variable];
|
||||
const unit = demo.getSliderUnit(demo.sliderData[inputOption.variable], inputOption.variable);
|
||||
sliderLabel.innerText = `${inputOption.variable}: ${data}${unit}`;
|
||||
|
||||
const ratio = (Number(target.value) - Number(inputOption.min)) / range;
|
||||
sliderInput.style.setProperty("--range-ratio", String(ratio));
|
||||
|
||||
demo.drawDemo(figure);
|
||||
});
|
||||
sliderContainer.appendChild(sliderInput);
|
||||
}
|
||||
|
||||
parentSliderContainer.append(sliderContainer);
|
||||
});
|
||||
|
||||
demo.append(parentSliderContainer);
|
||||
}
|
||||
|
||||
export function renderDemoPane(demoPane: DemoPane): void {
|
||||
@@ -55,30 +99,6 @@ export function renderDemoPane(demoPane: DemoPane): void {
|
||||
container.append(header);
|
||||
}
|
||||
|
||||
const tVariantContainer = document.createElement("div");
|
||||
tVariantContainer.className = "t-variant-choice";
|
||||
|
||||
const tVariantLabel = document.createElement("strong");
|
||||
tVariantLabel.innerText = "TValue Variant:";
|
||||
tVariantContainer.append(tVariantLabel);
|
||||
|
||||
const radioInputs = ["Parametric", "Euclidean"].map((tVariant) => {
|
||||
const id = `${demoPane.id}-${tVariant}`;
|
||||
const radioInput = document.createElement("input");
|
||||
radioInput.type = "radio";
|
||||
radioInput.id = id;
|
||||
radioInput.value = tVariant;
|
||||
radioInput.name = `TVariant - ${demoPane.id}`;
|
||||
radioInput.checked = tVariant === "Parametric";
|
||||
tVariantContainer.append(radioInput);
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.htmlFor = id;
|
||||
label.innerText = tVariant;
|
||||
tVariantContainer.append(label);
|
||||
return radioInput;
|
||||
});
|
||||
|
||||
const demoRow = document.createElement("div");
|
||||
demoRow.className = "demo-row";
|
||||
|
||||
@@ -87,21 +107,9 @@ export function renderDemoPane(demoPane: DemoPane): void {
|
||||
return;
|
||||
}
|
||||
const demoComponent = demoPane.buildDemo(demo);
|
||||
|
||||
radioInputs.forEach((radioInput: HTMLElement) => {
|
||||
radioInput.addEventListener("input", (event: Event): void => {
|
||||
demoPane.tVariant = (event.target as HTMLInputElement).value as TVariant;
|
||||
demoComponent.setAttribute("tvariant", demoPane.tVariant);
|
||||
});
|
||||
});
|
||||
demoRow.append(demoComponent);
|
||||
});
|
||||
|
||||
container.append(demoRow);
|
||||
|
||||
if (demoPane.chooseTVariant) {
|
||||
container.append(tVariantContainer);
|
||||
}
|
||||
|
||||
demoPane.append(container);
|
||||
}
|
||||
|
||||
@@ -11,26 +11,26 @@ export type WasmSubpathManipulatorKey = "set_anchor" | "set_in_handle" | "set_ou
|
||||
export const BEZIER_CURVE_TYPE = ["Linear", "Quadratic", "Cubic"] as const;
|
||||
export type BezierCurveType = typeof BEZIER_CURVE_TYPE[number];
|
||||
|
||||
export type TVariant = "Euclidean" | "Parametric";
|
||||
|
||||
export type BezierCallback = (bezier: WasmBezierInstance, options: Record<string, number>, mouseLocation?: [number, number], tVariant?: TVariant) => string;
|
||||
export type SubpathCallback = (subpath: WasmSubpathInstance, options: Record<string, number>, mouseLocation?: [number, number], tVariant?: TVariant) => string;
|
||||
export type BezierCallback = (bezier: WasmBezierInstance, options: Record<string, number>, mouseLocation?: [number, number]) => string;
|
||||
export type SubpathCallback = (subpath: WasmSubpathInstance, options: Record<string, number>, mouseLocation?: [number, number]) => string;
|
||||
|
||||
export type BezierDemoOptions = {
|
||||
[key in BezierCurveType]: {
|
||||
disabled?: boolean;
|
||||
sliderOptions?: SliderOption[];
|
||||
inputOptions?: InputOption[];
|
||||
customPoints?: number[][];
|
||||
};
|
||||
};
|
||||
|
||||
export type SliderOption = {
|
||||
min: number;
|
||||
max: number;
|
||||
step: number;
|
||||
default: number;
|
||||
export type InputOption = {
|
||||
variable: string;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
default?: number;
|
||||
unit?: string | string[];
|
||||
inputType?: "slider" | "dropdown";
|
||||
options?: string[];
|
||||
};
|
||||
|
||||
export function getCurveType(numPoints: number): BezierCurveType {
|
||||
@@ -61,7 +61,7 @@ export interface DemoArgs {
|
||||
|
||||
export interface BezierDemoArgs extends DemoArgs {
|
||||
points: number[][];
|
||||
sliderOptions: SliderOption[];
|
||||
inputOptions: InputOption[];
|
||||
}
|
||||
|
||||
export interface SubpathDemoArgs extends DemoArgs {
|
||||
@@ -70,7 +70,7 @@ export interface SubpathDemoArgs extends DemoArgs {
|
||||
}
|
||||
|
||||
export interface Demo extends HTMLElement {
|
||||
sliderOptions: SliderOption[];
|
||||
inputOptions: InputOption[];
|
||||
sliderData: Record<string, number>;
|
||||
sliderUnits: Record<string, string | string[]>;
|
||||
|
||||
@@ -85,7 +85,8 @@ export interface DemoPane extends HTMLElement {
|
||||
name: string;
|
||||
demos: DemoArgs[];
|
||||
id: string;
|
||||
chooseTVariant: boolean;
|
||||
tVariant: TVariant;
|
||||
buildDemo(demo: DemoArgs): Demo;
|
||||
}
|
||||
|
||||
export const BEZIER_T_VALUE_VARIANTS = ["Parametric", "Euclidean"] as const;
|
||||
export const SUBPATH_T_VALUE_VARIANTS = ["GlobalParametric", "GlobalEuclidean"] as const;
|
||||
|
||||
Reference in New Issue
Block a user