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:
Keavon Chambers
2026-02-23 19:21:51 -08:00
committed by GitHub
parent a1c1039ea1
commit 691d965bcf
21 changed files with 842 additions and 322 deletions

View File

@@ -58,7 +58,7 @@ pub mod subpath {
}
pub mod gradient {
pub use vector_types::GradientStops;
pub use vector_types::{GradientStop, GradientStops};
}
pub mod transform {

View File

@@ -41,7 +41,7 @@ mod adjust_std {
}
impl Adjust<Color> for GradientStops {
fn adjust(&mut self, map_fn: impl Fn(&Color) -> Color) {
for (_, color) in self.iter_mut() {
for color in self.color.iter_mut() {
*color = map_fn(color);
}
}

View File

@@ -8,7 +8,7 @@ use no_std_types::registry::types::PercentageF32;
#[cfg(feature = "std")]
use raster_types::{CPU, Raster};
#[cfg(feature = "std")]
use vector_types::GradientStops;
use vector_types::{GradientStop, GradientStops};
pub trait Blend<P: Pixel> {
fn blend(&self, under: &Self, blend_fn: impl Fn(P, P) -> P) -> Self;
@@ -63,18 +63,15 @@ mod blend_std {
}
impl Blend<Color> for GradientStops {
fn blend(&self, under: &Self, blend_fn: impl Fn(Color, Color) -> Color) -> Self {
let mut combined_stops = self.iter().map(|(position, _)| position).chain(under.iter().map(|(position, _)| position)).collect::<Vec<_>>();
combined_stops.dedup_by(|&mut a, &mut b| (a - b).abs() < 1e-6);
let mut combined_stops = self.position.iter().chain(under.position.iter()).copied().collect::<Vec<_>>();
combined_stops.dedup_by(|a, b| (*a - *b).abs() < 1e-6);
combined_stops.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
let stops = combined_stops
.into_iter()
.map(|&position| {
let over_color = self.evaluate(position);
let under_color = under.evaluate(position);
let color = blend_fn(over_color, under_color);
(position, color)
})
.collect::<Vec<_>>();
let stops = combined_stops.into_iter().map(|position| {
let over_color = self.evaluate(position);
let under_color = under.evaluate(position);
let color = blend_fn(over_color, under_color);
GradientStop { position, midpoint: 0.5, color }
});
GradientStops::new(stops)
}
}