New node: 'Gradient to Colors' for unwrapping a gradient ramp into its colors (#4425)

* New node: 'Gradient to Colors' for unwrapping a gradient ramp into its colors

* Update 'Gradient Midpoints' wording
This commit is contained in:
Keavon Chambers
2026-08-08 04:37:44 -07:00
committed by GitHub
parent ceb2de51fb
commit 759519782b
2 changed files with 35 additions and 3 deletions
+33 -1
View File
@@ -1057,12 +1057,18 @@ pub async fn flatten_gradient<T: IntoGraphicList>(_: impl Ctx, #[implementations
content.into_flattened_list()
}
/// Constructs a gradient from a `Color[]`, where the colors are evenly distributed as gradient stops across the range from 0 to 1.
/// Constructs a gradient from a `Color[]`, where each color becomes a gradient stop. A `position` attribute on the colors places their stops along the ramp and a `midpoint` attribute skews each transition, while colors carrying neither are distributed evenly across the 0 to 1 range.
#[node_macro::node(category("Gradient"), name("Colors to Gradient"))]
fn colors_to_gradient<T: IntoGraphicList>(_: impl Ctx, #[implementations(List<Graphic>, List<Color>)] colors: T) -> Item<Gradient> {
Item::new_from_element(Gradient::from(colors.into_flattened_list::<Color>()))
}
/// Unwraps a gradient into a `Color[]` of its stops, keeping any `position` and `midpoint` attributes that place them along the ramp. Attributes belonging to the gradient as a whole (like spread and interpolation), rather than its individual color stops, are not preserved.
#[node_macro::node(category("Gradient"), name("Gradient to Colors"))]
fn gradient_to_colors(_: impl Ctx, gradient: Item<Gradient>) -> List<Color> {
gradient.into_element().into_color_list()
}
#[cfg(test)]
mod test {
use super::*;
@@ -1186,4 +1192,30 @@ mod test {
let portion = list_slice((), list_of([1., 2., 3., 4., 5.]), Item::new_from_element(3.), Item::new_from_element(3.));
assert!(elements(&portion).is_empty());
}
#[test]
fn gradient_to_colors_round_trips_the_stops_with_their_placement() {
let mut gradient = Gradient::from(vec![Color::RED, Color::GREEN, Color::BLUE]);
gradient.set_positions(&[0., 0.25, 1.]);
gradient.set_midpoints(&[0.3, 0.5, 0.5]);
let colors = gradient_to_colors((), Item::new_from_element(gradient.clone()));
assert_eq!(elements(&colors), [Color::RED, Color::GREEN, Color::BLUE], "every stop should come out as its color");
let restored = colors_to_gradient((), colors);
assert_eq!(
restored.element(),
&gradient,
"wrapping the stops back up should restore the uneven placement rather than redistributing them"
);
}
#[test]
fn gradient_to_colors_leaves_an_untouched_ramp_without_placement_attributes() {
let gradient = Gradient::from(vec![Color::RED, Color::GREEN, Color::BLUE]);
assert!(!gradient.has_position_attribute(), "even spacing is stored as the attribute's absence");
let restored = colors_to_gradient((), gradient_to_colors((), Item::new_from_element(gradient.clone())));
assert_eq!(restored.element(), &gradient, "a default ramp should round trip without gaining attributes it never had");
}
}