typst/tests/suite/visualize/gradient.typ
2024-12-17 09:25:27 +00:00

661 lines
18 KiB
Typst

--- gradient-linear-angled ---
// Test gradients with direction.
#set page(width: 90pt)
#grid(
gutter: 3pt,
columns: 4,
..range(0, 360, step: 15).map(i => box(
height: 15pt,
width: 15pt,
fill: gradient.linear(angle: i * 1deg, (red, 0%), (blue, 100%)),
))
)
--- gradient-linear-oklab ---
// The tests below test whether hue rotation works correctly.
// Here we test in Oklab space for reference.
#set page(
width: 100pt,
height: 30pt,
fill: gradient.linear(red, purple, space: oklab)
)
--- gradient-linear-oklch ---
// Test in OkLCH space.
#set page(
width: 100pt,
height: 30pt,
fill: gradient.linear(red, purple, space: oklch)
)
--- gradient-linear-hsv ---
// Test in HSV space.
#set page(
width: 100pt,
height: 30pt,
fill: gradient.linear(red, purple, space: color.hsv)
)
--- gradient-linear-hsl ---
// Test in HSL space.
#set page(
width: 100pt,
height: 30pt,
fill: gradient.linear(red, purple, space: color.hsl)
)
--- gradient-linear-relative-parent ---
// The image should look as if there is a single gradient that is being used for
// both the page and the rectangles.
#let grad = gradient.linear(red, blue, green, purple, relative: "parent")
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
height: 50pt,
width: 50pt,
margin: 2.5pt,
fill: grad,
background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))
--- gradient-linear-relative-self ---
// The image should look as if there are multiple gradients, one for each
// rectangle.
#let grad = gradient.linear(red, blue, green, purple, relative: "self")
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
height: 50pt,
width: 50pt,
margin: 2.5pt,
fill: grad,
background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))
--- gradient-linear-relative-parent-block ---
// The image should look as if there are two nested gradients, one for the page
// and one for a nested block. The rotated rectangles are not visible because
// they are relative to the block.
#let grad = gradient.linear(red, blue, green, purple, relative: "parent")
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
height: 50pt,
width: 50pt,
margin: 5pt,
fill: grad,
background: place(top + left, my-rect),
)
#block(
width: 40pt,
height: 40pt,
inset: 2.5pt,
fill: grad,
)[
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))
]
--- gradient-linear-repeat-and-mirror-1 ---
// Test repeated gradients.
#rect(
height: 40pt,
width: 100%,
fill: gradient.linear(..color.map.inferno).repeat(2, mirror: true)
)
--- gradient-linear-repeat-and-mirror-2 ---
#rect(
height: 40pt,
width: 100%,
fill: gradient.linear(..color.map.rainbow).repeat(2, mirror: true),
)
--- gradient-linear-repeat-and-mirror-3 ---
#rect(
height: 40pt,
width: 100%,
fill: gradient.linear(..color.map.rainbow).repeat(5, mirror: true)
)
--- gradient-linear-sharp-and-repeat ---
#rect(
height: 40pt,
width: 100%,
fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: false)
)
--- gradient-linear-sharp-repeat-and-mirror ---
#rect(
height: 40pt,
width: 100%,
fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: true)
)
--- gradient-linear-sharp ---
#square(
size: 100pt,
fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10),
)
#square(
size: 100pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10),
)
#square(
size: 100pt,
fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10),
)
--- gradient-linear-sharp-and-smooth ---
#square(
size: 100pt,
fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%),
)
#square(
size: 100pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%),
)
#square(
size: 100pt,
fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%),
)
--- gradient-linear-stroke ---
#align(center + top, square(size: 50pt, fill: black, stroke: 5pt + gradient.linear(red, blue)))
--- gradient-fill-and-stroke ---
#align(
center + bottom,
square(
size: 50pt,
fill: gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%)),
stroke: 10pt + gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%))
)
)
--- gradient-linear-stroke-relative-parent ---
// The image should look as if there is a single gradient that is being used for
// both the circle stroke and the block fill.
#align(
center + horizon,
block(
width: 50pt,
height: 50pt,
fill: gradient.linear(red, blue).sharp(4),
circle(
radius: 18pt,
stroke: 5pt + gradient.linear(red, blue, relative: "parent").sharp(4),
)
)
)
--- gradient-linear-line ---
// Test gradient on lines
#set page(width: 100pt, height: 100pt)
#line(length: 100%, stroke: 1pt + gradient.linear(red, blue))
#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue))
#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue, relative: "parent"))
--- gradient-radial-hsl ---
#square(
size: 100pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl),
)
--- gradient-radial-center ---
#grid(
columns: 2,
square(
size: 50pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 0%)),
),
square(
size: 50pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 100%)),
),
square(
size: 50pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 0%)),
),
square(
size: 50pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 100%)),
),
)
--- gradient-radial-radius ---
#square(
size: 50pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 10%),
)
#square(
size: 50pt,
fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 72%),
)
--- gradient-radial-focal-center-and-radius ---
#circle(
radius: 25pt,
fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (35%, 35%), focal-radius: 5%),
)
#circle(
radius: 25pt,
fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (75%, 35%), focal-radius: 5%),
)
--- gradient-radial-relative-parent ---
// The image should look as if there is a single gradient that is being used for
// both the page and the rectangles.
#let grad = gradient.radial(red, blue, green, purple, relative: "parent");
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
height: 50pt,
width: 50pt,
margin: 2.5pt,
fill: grad,
background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))
--- gradient-radial-relative-self ---
// The image should look as if there are multiple gradients, one for each
// rectangle.
#let grad = gradient.radial(red, blue, green, purple, relative: "self");
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
height: 50pt,
width: 50pt,
margin: 2.5pt,
fill: grad,
background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))
--- gradient-radial-text ---
// Test that gradient fills on text.
// The solid bar gradients are used to make sure that all transforms are
// correct: if you can see the text through the bar, then the gradient is
// misaligned to its reference container.
#set page(width: 200pt, height: auto, margin: 10pt)
#set par(justify: true)
#set text(fill: gradient.radial(red, blue))
#lorem(30)
--- gradient-conic ---
#square(
size: 50pt,
fill: gradient.conic(..color.map.rainbow, space: color.hsv),
)
--- gradient-conic-center-shifted-1 ---
#square(
size: 50pt,
fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (10%, 10%)),
)
--- gradient-conic-center-shifted-2 ---
#square(
size: 50pt,
fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (90%, 90%)),
)
--- gradient-conic-angled ---
#square(
size: 50pt,
fill: gradient.conic(..color.map.rainbow, space: color.hsv, angle: 90deg),
)
--- gradient-conic-oklab ---
// Test in Oklab space for reference.
#set page(
width: 100pt,
height: 100pt,
fill: gradient.conic(red, purple, space: oklab)
)
--- gradient-conic-oklch ---
// Test in OkLCH space.
#set page(
width: 100pt,
height: 100pt,
fill: gradient.conic(red, purple, space: oklch)
)
--- gradient-conic-hsv ---
// Test in HSV space.
#set page(
width: 100pt,
height: 100pt,
fill: gradient.conic(red, purple, space: color.hsv)
)
--- gradient-conic-hsl ---
// Test in HSL space.
#set page(
width: 100pt,
height: 100pt,
fill: gradient.conic(red, purple, space: color.hsl)
)
--- gradient-conic-relative-parent ---
// The image should look as if there is a single gradient that is being used for
// both the page and the rectangles.
#let grad = gradient.conic(red, blue, green, purple, relative: "parent");
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
height: 50pt,
width: 50pt,
margin: 2.5pt,
fill: grad,
background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))
--- gradient-conic-relative-self ---
// The image should look as if there are multiple gradients, one for each
// rectangle.
#let grad = gradient.conic(red, blue, green, purple, relative: "self");
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
height: 50pt,
width: 50pt,
margin: 2.5pt,
fill: grad,
background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))
--- gradient-conic-stroke ---
#align(
center + bottom,
square(
size: 50pt,
fill: black,
stroke: 10pt + gradient.conic(red, blue)
)
)
--- gradient-conic-text ---
#set page(width: 200pt, height: auto, margin: 10pt)
#set par(justify: true)
#set text(fill: gradient.conic(red, blue, angle: 45deg))
#lorem(30)
--- gradient-text-bad-relative ---
// Make sure they don't work when `relative: "self"`.
// Hint: 17-61 make sure to set `relative: auto` on your text fill
// Error: 17-61 gradients and tilings on text must be relative to the parent
#set text(fill: gradient.linear(red, blue, relative: "self"))
--- gradient-text-global ---
// Test that gradient fills on text work for globally defined gradients.
#set page(width: 200pt, height: auto, margin: 10pt, background: {
rect(width: 100%, height: 30pt, fill: gradient.linear(red, blue))
})
#set par(justify: true)
#set text(fill: gradient.linear(red, blue))
#lorem(30)
--- gradient-text-dir ---
// Sanity check that the direction works on text.
#set page(width: 200pt, height: auto, margin: 10pt, background: {
rect(height: 100%, width: 30pt, fill: gradient.linear(dir: btt, red, blue))
})
#set par(justify: true)
#set text(fill: gradient.linear(dir: btt, red, blue))
#lorem(30)
--- gradient-text-in-container ---
// Test that gradient fills on text work for locally defined gradients.
#set page(width: auto, height: auto, margin: 10pt)
#show box: set text(fill: gradient.linear(..color.map.rainbow))
Hello, #box[World]!
--- gradient-text-rotate ---
// Test that gradients fills on text work with transforms.
#set page(width: auto, height: auto, margin: 10pt)
#show box: set text(fill: gradient.linear(..color.map.rainbow))
#rotate(45deg, box[World])
--- gradient-text-decoration ---
#set text(fill: gradient.linear(red, blue))
Hello #underline[World]! \
Hello #overline[World]! \
Hello #strike[World]! \
--- gradient-transformed ---
// Test whether gradients work well when they are contained within a transform.
#let grad = gradient.linear(red, blue, green, purple, relative: "parent");
#let my-rect = rect(width: 50pt, height: 50pt, fill: grad)
#set page(
height: 50pt,
width: 50pt,
margin: 2.5pt,
)
#place(top + right, scale(x: 200%, y: 130%, my-rect))
#place(bottom + center, rotate(45deg, my-rect))
#place(horizon + center, scale(x: 200%, y: 130%, rotate(45deg, my-rect)))
--- gradient-presets ---
// Test all gradient presets.
#set page(width: 100pt, height: auto, margin: 0pt)
#set text(fill: white, size: 18pt)
#set text(top-edge: "bounds", bottom-edge: "bounds")
#let presets = (
("turbo", color.map.turbo),
("cividis", color.map.cividis),
("rainbow", color.map.rainbow),
("spectral", color.map.spectral),
("viridis", color.map.viridis),
("inferno", color.map.inferno),
("magma", color.map.magma),
("plasma", color.map.plasma),
("rocket", color.map.rocket),
("mako", color.map.mako),
("vlag", color.map.vlag),
("icefire", color.map.icefire),
("flare", color.map.flare),
("crest", color.map.crest),
)
#stack(
spacing: 3pt,
..presets.map(((name, preset)) => block(
width: 100%,
height: 20pt,
fill: gradient.linear(..preset),
align(center + horizon, smallcaps(name)),
))
)
// Test that gradients are applied correctly on equations.
--- gradient-math-cancel ---
// Test on cancel
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box
$ a dot cancel(5) = cancel(25) 5 x + cancel(5) 1 $
--- gradient-math-frac ---
// Test on frac
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box
$ nabla dot bold(E) = frac(rho, epsilon_0) $
--- gradient-math-root ---
// Test on root
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box
$ x_"1,2" = frac(-b plus.minus sqrt(b^2 - 4 a c), 2 a) $
--- gradient-math-mat ---
// Test on matrix
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box
$ A = mat(
1, 2, 3;
4, 5, 6;
7, 8, 9
) $
--- gradient-math-underover ---
// Test on underover
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box
$ underline(X^2) $
$ overline("hello, world!") $
--- gradient-math-dir ---
// Test a different direction
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow, dir: ttb))
#show math.equation: box
$ A = mat(
1, 2, 3;
4, 5, 6;
7, 8, 9
) $
$ x_"1,2" = frac(-b plus.minus sqrt(b^2 - 4 a c), 2 a) $
--- gradient-math-misc ---
// Test miscellaneous
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box
$ hat(x) = bar x bar = vec(x, y, z) = tilde(x) = dot(x) $
$ x prime = vec(1, 2, delim: "[") $
$ sum_(i in NN) 1 + i $
$ attach(
Pi, t: alpha, b: beta,
tl: 1, tr: 2+3, bl: 4+5, br: 6,
) $
--- gradient-math-radial ---
// Test radial gradient
#show math.equation: set text(fill: gradient.radial(..color.map.rainbow, center: (30%, 30%)))
#show math.equation: box
$ A = mat(
1, 2, 3;
4, 5, 6;
7, 8, 9
) $
--- gradient-math-conic ---
// Test conic gradient
#show math.equation: set text(fill: gradient.conic(red, blue, angle: 45deg))
#show math.equation: box
$ A = mat(
1, 2, 3;
4, 5, 6;
7, 8, 9
) $
--- gradient-kind ---
// Test gradient functions.
#test(gradient.linear(red, green, blue).kind(), gradient.linear)
--- gradient-stops ---
#test(gradient.linear(red, green, blue).stops(), ((red, 0%), (green, 50%), (blue, 100%)))
--- gradient-sample ---
#test(gradient.linear(red, green, blue, space: rgb).sample(0%), red)
#test(gradient.linear(red, green, blue, space: rgb).sample(25%), rgb("#97873b"))
#test(gradient.linear(red, green, blue, space: rgb).sample(50%), green)
#test(gradient.linear(red, green, blue, space: rgb).sample(75%), rgb("#17a08c"))
#test(gradient.linear(red, green, blue, space: rgb).sample(100%), blue)
--- gradient-space ---
#test(gradient.linear(red, green, space: rgb).space(), rgb)
#test(gradient.linear(red, green, space: oklab).space(), oklab)
#test(gradient.linear(red, green, space: oklch).space(), oklch)
#test(gradient.linear(red, green, space: cmyk).space(), cmyk)
#test(gradient.linear(red, green, space: luma).space(), luma)
#test(gradient.linear(red, green, space: color.linear-rgb).space(), color.linear-rgb)
#test(gradient.linear(red, green, space: color.hsl).space(), color.hsl)
#test(gradient.linear(red, green, space: color.hsv).space(), color.hsv)
--- gradient-relative ---
#test(gradient.linear(red, green, relative: "self").relative(), "self")
#test(gradient.linear(red, green, relative: "parent").relative(), "parent")
#test(gradient.linear(red, green).relative(), auto)
--- gradient-angle ---
#test(gradient.linear(red, green).angle(), 0deg)
#test(gradient.linear(red, green, dir: ltr).angle(), 0deg)
#test(gradient.linear(red, green, dir: rtl).angle(), 180deg)
#test(gradient.linear(red, green, dir: ttb).angle(), 90deg)
#test(gradient.linear(red, green, dir: btt).angle(), 270deg)
--- gradient-repeat ---
#test(
gradient.linear(red, green, blue).repeat(2).stops(),
((red, 0%), (green, 25%), (blue, 50%), (red, 50%), (green, 75%), (blue, 100%))
)
#test(
gradient.linear(red, green, blue).repeat(2, mirror: true).stops(),
((red, 0%), (green, 25%), (blue, 50%), (green, 75%), (red, 100%))
)
--- issue-2902-gradient-oklch-panic ---
// Minimal reproduction of #2902
#set page(width: 15cm, height: auto, margin: 1em)
#set block(width: 100%, height: 1cm, above: 2pt)
// Oklch
#block(fill: gradient.linear(red, purple, space: oklch))
#block(fill: gradient.linear(..color.map.rainbow, space: oklch))
#block(fill: gradient.linear(..color.map.plasma, space: oklch))
--- issue-2902-gradient-oklab-panic ---
#set page(width: 15cm, height: auto, margin: 1em)
#set block(width: 100%, height: 1cm, above: 2pt)
// Oklab
#block(fill: gradient.linear(red, purple, space: oklab))
#block(fill: gradient.linear(..color.map.rainbow, space: oklab))
#block(fill: gradient.linear(..color.map.plasma, space: oklab))
--- issue-gradient-cmyk-encode ---
// Test that CMYK works on gradients
#set page(margin: 0pt, width: 100pt, height: auto)
#let violet = cmyk(75%, 80%, 0%, 0%)
#let blue = cmyk(75%, 30%, 0%, 0%)
#rect(
width: 100%,
height: 10pt,
fill: gradient.linear(violet, blue)
)
#rect(
width: 100%,
height: 10pt,
fill: gradient.linear(rgb(violet), rgb(blue))
)
// In PDF format, this gradient can look different from the others.
// This is because PDF readers do weird things with CMYK.
#rect(
width: 100%,
height: 10pt,
fill: gradient.linear(violet, blue, space: cmyk)
)