A gradient describes a linear or radial colour
transition and can be used as the fill_pattern of any
graphical that accepts a colour fill. The renderer draws
the shape's outline as usual and fills it by sampling the gradient
across the shape's area.
The points and radii of a gradient are interpreted according to
gradient<-units:
user (default) — they are coordinates of the device
on which the shape is displayed, the coordinate system the shape itself
uses. The pattern scrolls and transforms with the device, but it does
not move with the shape: a shape that is moved shows another part of the
gradient.
bounding_box — they are fractions of the box around
the shape being filled: (0,0) is its top-left and (1,1) its bottom-right
corner. The pattern moves and scales with the shape, and a single
gradient fills shapes of any size and position in the same way. As in
SVG, a radial gradient becomes elliptical if the box is not square. A
shape without area, e.g., a horizontal line,
uses user units. A canvas sets its gradient->source
before the path exists and thus always uses user units.
Two kinds are supported:
linear — the colour interpolates along the axis from gradient<-p0
to
gradient<-p1.
Points at gradient<-p0
receive the stop at fraction 0.0; points at gradient<-p1
the stop at 1.0; intermediate points a
weighted mix of the bracketing stops. Perpendicular to the axis the
colour is constant.
radial — the colour interpolates from a start circle
(gradient<-p0, gradient<-r0)
to an end circle (gradient<-p1, gradient<-r1).
The two circles may be concentric (the common case) or offset (creates
an eccentric radial highlight).
A gradient needs at least one stop to render anything
visible; two stops give a two-colour transition; more stops give
piecewise interpolation.
Example: a top-to-bottom yellow-to-red fill on a 100×60 box.
new(P, picture), send(P, open),
new(G, gradient(linear, point(0,0), point(0,1),
units := bounding_box)),
send(G, add_stop, 0, colour(yellow)),
send(G, add_stop, 1, colour(red)),
send(P, display, new(B, box(100, 60)), point(20, 20)),
send(B, pen, 0),
send(B, fill, G).
Because a gradient is a data object rather than a graphical, it may
be attached to as many shapes as desired. Shapes sharing a gradient with user
units sample one pattern that covers the device; with
bounding_box units each shape gets the whole gradient.
Changing a gradient does not redraw the shapes that use it.
linear)
or between two circles (radial). Fixed at construction —
build a fresh gradient to change kind.<-p0
and
gradient<-p1
to the two corners of the shape; the perpendicular component is unused.none),
the colour of the nearest stop (pad), the gradient repeated
(repeat), or repeated and mirrored every other time (reflect).
Defaults: pad
<-p0, gradient<-p1, gradient<-r0
and gradient<-r1
are device coordinates or fractions of the box around the shape being
filled. See the class description.
Defaults: user
tuple(fraction, colour) — the colour stops.
Fractions are numbers in 0..1 (values outside are silently clamped by
the renderer); the chain need not be sorted but the visual result
depends on stop order for repeated fractions. Empty chains render as
fully transparent.
r0 and r1 are only
meaningful when
kind is radial; pass @default
for a linear gradient and they are stored as @nil.
If stops is @default
an empty chain is created and stops must be added later with gradient->add_stop
or gradient->stops.
See the class introduction for a runnable example.
tuple(fraction, colour) to gradient<-stops.
Convenience wrapper equivalent to
send(G?stops, append, new(_, tuple(F, C)))
for the common incremental-build pattern.
tuple(fraction, colour) objects; the renderer skips
anything else silently.