0.5) ? $delta / (2 - $max - $min) : $delta / ($max + $min); switch ($max) { case $r: $h = ($g - $b) / $delta + (($g < $b) ? 6 : 0); break; case $g: $h = ($b - $r) / $delta + 2; break; case $b: $h = ($r - $g) / $delta + 4; break; } $h /= 6; } return [$h, $s, $l]; } function hslToRgb($h, $s, $l) { if ($s == 0) { // No saturation, this is a shade of gray $r = $g = $b = $l * 255; } else { $q = ($l < 0.5) ? $l * (1 + $s) : $l + $s - ($l * $s); $p = (2 * $l) - $q; $r = round(255 * hueToRgb($p, $q, $h + (1 / 3))); $g = round(255 * hueToRgb($p, $q, $h)); $b = round(255 * hueToRgb($p, $q, $h - (1 / 3))); } return [(int)$r, (int)$g, (int)$b]; } function hueToRgb($p, $q, $t) { if ($t < 0) { $t += 1; } if ($t > 1) { $t -= 1; } if ($t < 1 / 6) { return $p + ($q - $p) * 6 * $t; } if ($t < 1 / 2) { return $q; } if ($t < 2 / 3) { return $p + ($q - $p) * (2 / 3 - $t) * 6; } return $p; } function darkModeColor($r, $g, $b) { // Convert RGB to HSL [$h, $s, $l] = rgbToHsl($r, $g, $b); // Invert lightness $l = 1 - $l; // Convert back to RGB return hslToRgb($h, $s, $l); } function interpolateRainbow($t) { $hue = $t * 360; return hsvToRgb($hue, 1, 1); } function interpolateSinebow($t) { $t = 0.5 * ($t + 1); $t = sin($t * M_PI); $a = 0.5 * $t * $t; $b = 0.5 * $t; $c = 0.5 * $t * sqrt(1 - $t * $t); return [ 255 * (0.5 + $a), 255 * (0.5 + $b), 255 * (0.5 + $c), ]; } function hsvToRgb($h, $s, $v) { $c = $v * $s; $x = $c * (1 - abs(fmod($h / 60, 2) - 1)); $m = $v - $c; if ($h < 60) { $rgb = [$c, $x, 0]; } elseif ($h < 120) { $rgb = [$x, $c, 0]; } elseif ($h < 180) { $rgb = [0, $c, $x]; } elseif ($h < 240) { $rgb = [0, $x, $c]; } elseif ($h < 300) { $rgb = [$x, 0, $c]; } else { $rgb = [$c, 0, $x]; } return [ 255 * ($rgb[0] + $m), 255 * ($rgb[1] + $m), 255 * ($rgb[2] + $m), ]; } /** * Generates an array of color codes based on the given interpolator function. * * @param int $n The number of colors to generate in the palette. * If 0 or negative, an empty array will be returned. * If 1, the palette will have a single color generated by the interpolator function. * @param callable $interpolator A function that takes a float parameter between 0 and 1 (inclusive) and returns an * array with three elements (red, green, blue) representing the color. Each element * should be an integer between 0 and 255. * * @return array An array of color codes in the format "#RRGGBB", where RR, GG, and BB are two-digit hexadecimal * values representing the red, green, and blue components of the color. */ function generate_palette($n, $interpolator) { if ($n <= 0) { return []; } $palette = []; if ($n == 1) { $color = call_user_func($interpolator, 0); $palette[] = sprintf("#%02x%02x%02x", $color[0], $color[1], $color[2]); return $palette; } for ($i = 0; $i < $n; $i++) { $t = $i / ($n - 1); $color = call_user_func($interpolator, $t); $palette[] = sprintf("#%02x%02x%02x", $color[0], $color[1], $color[2]); } return $palette; } function interpolateSpectral($t) { $colors = [ [158, 1, 66], [213, 62, 79], [244, 109, 67], [253, 174, 97], [254, 224, 139], [255, 255, 191], [230, 245, 152], [171, 221, 164], [102, 194, 165], [50, 136, 189], [94, 79, 162], ]; $segments = count($colors) - 1; $index = ($t * $segments); $lower = floor($index); $upper = ceil($index); $t = $index - $lower; if ($lower == $upper) { return $colors[$lower]; } return interpolate($t, $colors[$lower], $colors[$upper]); } function interpolate($t, $color1, $color2) { return [ $color1[0] + $t * ($color2[0] - $color1[0]), $color1[1] + $t * ($color2[1] - $color1[1]), $color1[2] + $t * ($color2[2] - $color1[2]), ]; } function interpolateCubehelix($t, $startAngle = 300, $rotations = -1.5, $hue = 1, $gamma = 1) { $angle = 2 * M_PI * (($startAngle / 360) + $rotations * $t); $fr = $t ** $gamma; $a = $hue * $fr * (1 - $fr) / 2; $cosA = cos($angle); $sinA = sin($angle); $r = $fr + $a * (-0.14861 * $cosA + 1.78277 * $sinA); $g = $fr + $a * (-0.29227 * $cosA - 0.90649 * $sinA); $b = $fr + $a * (1.97294 * $cosA); return [ (int)round(255 * max(0, min(1, $r))), (int)round(255 * max(0, min(1, $g))), (int)round(255 * max(0, min(1, $b))), ]; } // The interpolateCubehelixDefault function function interpolateCubehelixDefault($t) { return interpolateCubehelix($t, 300, -0.5, 1.7, 0.4); } function interpolateCubehelixGreen($t) { return interpolateCubehelix($t, 120, -0.5, 1.7, 0.4); } function interpolateCubehelixBlueToRed($t) { return interpolateCubehelix($t, 240, 0.5, 1.5, 1.0); } function interpolateCubehelixRedToGreen($t) { return interpolateCubehelix($t, 0, 1.0, 1.5, 1.0); } function interpolateCubehelixGrayscale($t) { return interpolateCubehelix($t, 0, 0, 0, 1.0); } function interpolateCubehelixViridisLike($t) { return interpolateCubehelix($t, 260, -0.5, 2.0, 1.0); } function interpolateCubehelixSunset($t) { return interpolateCubehelix($t, 0, 1.5, 2.0, 1.0); } function interpolateCubehelixCoolTones($t) { return interpolateCubehelix($t, 200, -0.5, 1.5, 1.0); } function interpolateCubehelixEarthTones($t) { return interpolateCubehelix($t, 100, -0.5, 1.5, 0.8); } function interpolateCubehelixCoolToWarm($t) { return interpolateCubehelix($t, 220, 0.5, 1.5, 1.0); } function interpolateCubehelixDivergingBlueYellow($t) { $middle_t = 0.5; if ($t < $middle_t) { return interpolateCubehelix(($middle_t - $t) * 2, 240, -0.5, 1.5, 1.0); } else { return interpolateCubehelix(($t - $middle_t) * 2, 60, 0.5, 1.5, 1.0); } } function interpolateCubehelixOcean($t) { return interpolateCubehelix($t, 210, -1.0, 1.5, 1.0); } function interpolateCubehelixMagmaLike($t) { return interpolateCubehelix($t, 0, 1.5, 1.8, 1.0); } function interpolateCubehelixPastel($t) { return interpolateCubehelix($t, 300, 0.8, 0.7, 1.2); } function divergingColorMap($t, $colors) { $n = count($colors) - 1; $index = min($n - 1, max(0, floor($t * $n))); $t = ($t * $n) - $index; return interpolateColor($t, $colors[$index], $colors[$index + 1]); } function interpolateRdYlBu($t) { $colors = [ [165, 0, 38], [215, 48, 39], [244, 109, 67], [253, 174, 97], [254, 224, 144], [255, 255, 191], [224, 243, 248], [171, 217, 233], [116, 173, 209], [69, 117, 180], [49, 54, 149], ]; return divergingColorMap($t, $colors); } function interpolateRdBu($t) { $colors = [ [103, 0, 31], [178, 24, 43], [214, 96, 77], [244, 165, 130], [253, 219, 199], [247, 247, 247], [209, 229, 240], [146, 197, 222], [67, 147, 195], [33, 102, 172], [5, 48, 97], ]; return divergingColorMap($t, $colors); } function interpolatePuOr($t) { $colors = [ [127, 59, 8], [179, 88, 6], [224, 130, 20], [253, 184, 99], [254, 224, 182], [247, 247, 247], [216, 218, 235], [178, 171, 210], [128, 115, 172], [84, 39, 136], [45, 0, 75], ]; return divergingColorMap($t, $colors); } function interpolateBrBG($t) { $colors = [ [84, 48, 5], [140, 81, 10], [191, 129, 45], [223, 194, 125], [246, 232, 195], [245, 245, 245], [199, 234, 229], [128, 205, 193], [53, 151, 143], [1, 102, 94], [0, 60, 48], ]; return divergingColorMap($t, $colors); } function interpolateCividis($t) { $colors = [ [0, 32, 76], [0, 42, 102], [0, 52, 110], [12, 69, 132], [38, 87, 141], [61, 104, 147], [83, 121, 153], [109, 138, 158], [134, 154, 163], [160, 170, 168], [185, 186, 172], ]; return divergingColorMap($t, $colors); }