Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.00% covered (success)
95.00%
19 / 20
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ConicGradient
95.00% covered (success)
95.00%
19 / 20
50.00% covered (danger)
50.00%
1 / 2
11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toCss
94.74% covered (success)
94.74%
18 / 19
0.00% covered (danger)
0.00%
0 / 1
10.01
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Css\Value;
6
7/**
8 * `conic-gradient([from <angle>]? [at <position>]?, <stops>)`
9 * per CSS Backgrounds 4 + CSS Images 4 ยง3.5.
10 *
11 * A conic gradient sweeps a colour around a centre point. The
12 * `from` angle controls the starting orientation (default 0deg โ€”
13 * the 12 o'clock direction). The `at` position controls the
14 * centre (default 50% 50% โ€” the centre of the box). Stops are
15 * angular per the spec; this storage tags them with the same
16 * `GradientStop` type linear / radial use, with the `position`
17 * field carrying the angle as a percentage of the full sweep
18 * (0 to 1 maps to 0deg to 360deg).
19 */
20final readonly class ConicGradient extends Gradient
21{
22    /**
23     * @param float $fromAngleDeg Starting orientation, normalised
24     *                            to [0, 360).
25     * @param float|null $centerX `at <position>` x coordinate
26     *                            (percentage 0-1). Null = default
27     *                            (centre, 0.5).
28     * @param float|null $centerY `at <position>` y coordinate
29     *                            (percentage 0-1). Null = default
30     *                            (centre, 0.5).
31     * @param list<GradientStop> $stops
32     */
33    public function __construct(
34        public float $fromAngleDeg,
35        public ?float $centerX,
36        public ?float $centerY,
37        public array $stops,
38        public bool $repeating = false,
39        public ?ColorSpace $interpolationSpace = null,
40        public ?HueInterpolation $hueInterpolation = null,
41    ) {}
42
43    public function toCss(): string
44    {
45        $prefix = $this->repeating ? 'repeating-conic-gradient' : 'conic-gradient';
46        $head = [];
47        if ($this->fromAngleDeg !== 0.0) {
48            $angle = fmod($this->fromAngleDeg, 1.0) === 0.0
49                ? (string) (int) $this->fromAngleDeg
50                : (string) $this->fromAngleDeg;
51            $head[] = 'from ' . $angle . 'deg';
52        }
53        if ($this->centerX !== null || $this->centerY !== null) {
54            $cx = ($this->centerX ?? 0.5) * 100;
55            $cy = ($this->centerY ?? 0.5) * 100;
56            $head[] = 'at ' . (fmod($cx, 1.0) === 0.0 ? (int) $cx : $cx) . '% '
57                . (fmod($cy, 1.0) === 0.0 ? (int) $cy : $cy) . '%';
58        }
59        $method = InterpolationMethodCss::serialise($this->interpolationSpace, $this->hueInterpolation);
60        if ($method !== '') {
61            // Drop leading space โ€” InterpolationMethodCss::serialise
62            // returns " in <space>"; we already join with spaces.
63            $head[] = ltrim($method);
64        }
65        $stops = implode(', ', array_map(static fn(GradientStop $s): string => $s->toCss(), $this->stops));
66        return $head === []
67            ? sprintf('%s(%s)', $prefix, $stops)
68            : sprintf('%s(%s, %s)', $prefix, implode(' ', $head), $stops);
69    }
70}