mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 22:48:12 +08:00
Add support for gradients with midpoints and add draggable diamonds to the color picker dialog (#3813)
* Refactor GradientStops to use struct-of-arrays and include midpoint * Implement interaction and rendering * Make color picker saturation-value color picking snap to original position and show both axis lines Make color picker saturation-value color picking snap to original position and show both axis lines * Add graphite:midpoint attribute to SVG exports * Add graphite:midpoint parsing to SVG importer
This commit is contained in:
+31
-42
@@ -2,7 +2,7 @@
|
||||
|
||||
import { Transform, Type, plainToClass } from "class-transformer";
|
||||
|
||||
import { type EditorHandle } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import { sampleInterpolatedGradient, type EditorHandle } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import { type PopoverButtonStyle, type IconName, type IconSize } from "@graphite/icons";
|
||||
|
||||
export class JsMessage {
|
||||
@@ -355,46 +355,40 @@ export type RGBA = { r: number; g: number; b: number; a: number };
|
||||
export type RGB = { r: number; g: number; b: number };
|
||||
|
||||
export class Gradient {
|
||||
readonly stops!: { position: number; color: Color }[];
|
||||
position!: number[];
|
||||
midpoint!: number[];
|
||||
color!: Color[];
|
||||
|
||||
constructor(stops: { position: number; color: Color }[]) {
|
||||
this.stops = stops;
|
||||
constructor(position: number[], midpoint: number[], color: Color[]) {
|
||||
this.position = position;
|
||||
this.midpoint = midpoint;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
toLinearGradientCSS(): string {
|
||||
if (this.stops.length === 1) {
|
||||
return `linear-gradient(to right, ${this.stops[0].color.toHexOptionalAlpha()} 0%, ${this.stops[0].color.toHexOptionalAlpha()} 100%)`;
|
||||
if (this.position.length === 1) {
|
||||
return `linear-gradient(to right, ${this.color[0].toHexOptionalAlpha()} 0%, ${this.color[0].toHexOptionalAlpha()} 100%)`;
|
||||
}
|
||||
const pieces = this.stops.map((stop) => `${stop.color.toHexOptionalAlpha()} ${stop.position * 100}%`);
|
||||
return `linear-gradient(to right, ${pieces.join(", ")})`;
|
||||
|
||||
const pieces = sampleInterpolatedGradient(new Float64Array(this.position), new Float64Array(this.midpoint), this.color, false);
|
||||
return `linear-gradient(to right, ${pieces})`;
|
||||
}
|
||||
|
||||
toLinearGradientCSSNoAlpha(): string {
|
||||
if (this.stops.length === 1) {
|
||||
return `linear-gradient(to right, ${this.stops[0].color.toHexNoAlpha()} 0%, ${this.stops[0].color.toHexNoAlpha()} 100%)`;
|
||||
if (this.position.length === 1) {
|
||||
return `linear-gradient(to right, ${this.color[0].toHexNoAlpha()} 0%, ${this.color[0].toHexNoAlpha()} 100%)`;
|
||||
}
|
||||
const pieces = this.stops.map((stop) => `${stop.color.toHexNoAlpha()} ${stop.position * 100}%`);
|
||||
return `linear-gradient(to right, ${pieces.join(", ")})`;
|
||||
|
||||
const pieces = sampleInterpolatedGradient(new Float64Array(this.position), new Float64Array(this.midpoint), this.color, true);
|
||||
return `linear-gradient(to right, ${pieces})`;
|
||||
}
|
||||
|
||||
firstColor(): Color | undefined {
|
||||
return this.stops[0]?.color;
|
||||
return this.color[0];
|
||||
}
|
||||
|
||||
lastColor(): Color | undefined {
|
||||
return this.stops[this.stops.length - 1]?.color;
|
||||
}
|
||||
|
||||
atIndex(index: number): { position: number; color: Color } | undefined {
|
||||
return this.stops[index];
|
||||
}
|
||||
|
||||
colorAtIndex(index: number): Color | undefined {
|
||||
return this.stops[index]?.color;
|
||||
}
|
||||
|
||||
positionAtIndex(index: number): number | undefined {
|
||||
return this.stops[index]?.position;
|
||||
return this.color[this.color.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,10 +493,6 @@ export class Color {
|
||||
return Math.abs(this.red - other.red) < 1e-6 && Math.abs(this.green - other.green) < 1e-6 && Math.abs(this.blue - other.blue) < 1e-6 && Math.abs(this.alpha - other.alpha) < 1e-6;
|
||||
}
|
||||
|
||||
lerp(other: Color, t: number): Color {
|
||||
return new Color(this.red * (1 - t) + other.red * t, this.green * (1 - t) + other.green * t, this.blue * (1 - t) + other.blue * t, this.alpha * (1 - t) + other.alpha * t);
|
||||
}
|
||||
|
||||
toHexNoAlpha(): string | undefined {
|
||||
if (this.none) return undefined;
|
||||
|
||||
@@ -951,20 +941,19 @@ export class ColorInput extends WidgetProps {
|
||||
// Content
|
||||
@Transform(({ value }) => {
|
||||
if (value instanceof Gradient) return value;
|
||||
const gradient = value["Gradient"];
|
||||
const gradient: Gradient | undefined = value["Gradient"];
|
||||
if (gradient) {
|
||||
const stops = gradient.map(([position, color]: [number, color: { red: number; green: number; blue: number; alpha: number }]) => ({
|
||||
position,
|
||||
color: new Color(color.red, color.green, color.blue, color.alpha),
|
||||
}));
|
||||
return new Gradient(stops);
|
||||
return new Gradient(
|
||||
gradient.position,
|
||||
gradient.midpoint,
|
||||
gradient.color.map((color: any) => new Color(color.red, color.green, color.blue, color.alpha)),
|
||||
);
|
||||
}
|
||||
|
||||
if (value instanceof Color) return value;
|
||||
|
||||
const solid = value["Solid"];
|
||||
if (solid) {
|
||||
return new Color(solid.red, solid.green, solid.blue, solid.alpha);
|
||||
}
|
||||
if (solid) return new Color(solid.red, solid.green, solid.blue, solid.alpha);
|
||||
|
||||
return new Color("none");
|
||||
})
|
||||
@@ -1008,10 +997,10 @@ export function contrastingOutlineFactor(value: FillChoice, proximityColor: stri
|
||||
};
|
||||
|
||||
if (value instanceof Gradient) {
|
||||
if (value.stops.length === 0) return 0;
|
||||
if (value.color.length === 0) return 0;
|
||||
|
||||
const first = contrast(value.stops[0].color);
|
||||
const last = contrast(value.stops[value.stops.length - 1].color);
|
||||
const first = contrast(value.color[0]);
|
||||
const last = contrast(value.color[value.color.length - 1]);
|
||||
|
||||
return Math.min(first, last);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user