初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
export function clamp(value, minimum, maximum) {
|
||||
return Math.min(maximum, Math.max(minimum, Number(value)));
|
||||
}
|
||||
|
||||
export function normalizeHex(value) {
|
||||
const match = /^#?([0-9a-f]{6})$/i.exec(String(value).trim());
|
||||
return match ? `#${match[1].toUpperCase()}` : null;
|
||||
}
|
||||
|
||||
export function rgbToHex({ r, g, b }) {
|
||||
return `#${[r, g, b]
|
||||
.map((channel) => Math.round(clamp(channel, 0, 255)).toString(16).padStart(2, "0"))
|
||||
.join("")}`.toUpperCase();
|
||||
}
|
||||
|
||||
export function hexToRgb(value) {
|
||||
const hex = normalizeHex(value);
|
||||
if (!hex) throw new TypeError("颜色必须是 #RRGGBB");
|
||||
return {
|
||||
r: Number.parseInt(hex.slice(1, 3), 16),
|
||||
g: Number.parseInt(hex.slice(3, 5), 16),
|
||||
b: Number.parseInt(hex.slice(5, 7), 16),
|
||||
};
|
||||
}
|
||||
|
||||
export function rgbToHsv({ r, g, b }) {
|
||||
const red = clamp(r, 0, 255) / 255;
|
||||
const green = clamp(g, 0, 255) / 255;
|
||||
const blue = clamp(b, 0, 255) / 255;
|
||||
const maximum = Math.max(red, green, blue);
|
||||
const minimum = Math.min(red, green, blue);
|
||||
const delta = maximum - minimum;
|
||||
let hue = 0;
|
||||
if (delta !== 0) {
|
||||
if (maximum === red) hue = 60 * (((green - blue) / delta) % 6);
|
||||
else if (maximum === green) hue = 60 * ((blue - red) / delta + 2);
|
||||
else hue = 60 * ((red - green) / delta + 4);
|
||||
}
|
||||
if (hue < 0) hue += 360;
|
||||
return {
|
||||
h: Math.round(hue),
|
||||
s: Math.round(maximum === 0 ? 0 : (delta / maximum) * 100),
|
||||
v: Math.round(maximum * 100),
|
||||
};
|
||||
}
|
||||
|
||||
export function hsvToRgb({ h, s, v }) {
|
||||
const hue = ((Number(h) % 360) + 360) % 360;
|
||||
const saturation = clamp(s, 0, 100) / 100;
|
||||
const value = clamp(v, 0, 100) / 100;
|
||||
const chroma = value * saturation;
|
||||
const segment = hue / 60;
|
||||
const secondary = chroma * (1 - Math.abs((segment % 2) - 1));
|
||||
let channels = [0, 0, 0];
|
||||
if (segment < 1) channels = [chroma, secondary, 0];
|
||||
else if (segment < 2) channels = [secondary, chroma, 0];
|
||||
else if (segment < 3) channels = [0, chroma, secondary];
|
||||
else if (segment < 4) channels = [0, secondary, chroma];
|
||||
else if (segment < 5) channels = [secondary, 0, chroma];
|
||||
else channels = [chroma, 0, secondary];
|
||||
const match = value - chroma;
|
||||
return {
|
||||
r: Math.round((channels[0] + match) * 255),
|
||||
g: Math.round((channels[1] + match) * 255),
|
||||
b: Math.round((channels[2] + match) * 255),
|
||||
};
|
||||
}
|
||||
|
||||
export function updateRecentColors(colors, value, limit = 10) {
|
||||
const normalized = normalizeHex(value);
|
||||
if (!normalized) return Array.isArray(colors) ? colors.slice(0, limit) : [];
|
||||
const existing = Array.isArray(colors)
|
||||
? colors.map(normalizeHex).filter(Boolean).filter((color) => color !== normalized)
|
||||
: [];
|
||||
return [normalized, ...existing].slice(0, limit);
|
||||
}
|
||||
Reference in New Issue
Block a user