99 lines
2.9 KiB
JavaScript
99 lines
2.9 KiB
JavaScript
|
function hexToRgb(hex) {
|
||
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||
|
return result ? {
|
||
|
r: parseInt(result[1], 16),
|
||
|
g: parseInt(result[2], 16),
|
||
|
b: parseInt(result[3], 16)
|
||
|
} : null;
|
||
|
}
|
||
|
|
||
|
function interpolateColor(startRgb, endRgb, t) {
|
||
|
return {
|
||
|
r: Math.round(startRgb.r + (endRgb.r - startRgb.r) * t),
|
||
|
g: Math.round(startRgb.g + (endRgb.g - startRgb.g) * t),
|
||
|
b: Math.round(startRgb.b + (endRgb.b - startRgb.b) * t)
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function rgbToString(rgb) {
|
||
|
return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
|
||
|
}
|
||
|
|
||
|
function getBandColorAtT(startRgb, endRgb, bands, t) {
|
||
|
const bandIndex = Math.floor(t * bands);
|
||
|
const bandT = bandIndex / (bands - 1);
|
||
|
const clampedBandT = Math.max(0, Math.min(1, bandT));
|
||
|
return interpolateColor(startRgb, endRgb, clampedBandT);
|
||
|
}
|
||
|
|
||
|
function applyFunction(t, funcType) {
|
||
|
switch ( funcType) {
|
||
|
case 'linear':
|
||
|
return t;
|
||
|
case 'quad':
|
||
|
return t * t;
|
||
|
case 'cubic':
|
||
|
return t * t * t;
|
||
|
case 'sin':
|
||
|
return -Math.cos(t * Math.PI) / 2.0 + 0.5;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function renderGradient() {
|
||
|
const canvas = document.getElementById('gradient-canvas');
|
||
|
const ctx = canvas.getContext('2d');
|
||
|
const startColor = document.getElementById('start-color').value;
|
||
|
const endColor = document.getElementById('end-color').value;
|
||
|
const bands = parseInt(document.getElementById('bands').value);
|
||
|
const funcType = document.getElementById('func').value;
|
||
|
|
||
|
const startRgb = hexToRgb(startColor);
|
||
|
const endRgb = hexToRgb(endColor);
|
||
|
|
||
|
if (!startRgb || !endRgb || bands < 1) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const width = canvas.width;
|
||
|
const height = canvas.height;
|
||
|
|
||
|
const imageData = ctx.createImageData(width, height);
|
||
|
const data = imageData.data;
|
||
|
|
||
|
for (let y = 0; y < height; y++) {
|
||
|
const t = y / (height - 1);
|
||
|
const u = applyFunction(t, funcType);
|
||
|
const color = getBandColorAtT(startRgb, endRgb, bands, u);
|
||
|
|
||
|
for (let x = 0; x < width; x++) {
|
||
|
const index = (y * width + x) * 4;
|
||
|
data[index] = color.r;
|
||
|
data[index + 1] = color.g;
|
||
|
data[index + 2] = color.b;
|
||
|
data[index + 3] = 255;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ctx.putImageData(imageData, 0, 0);
|
||
|
}
|
||
|
|
||
|
function downloadCanvas() {
|
||
|
const canvas = document.getElementById('gradient-canvas');
|
||
|
const link = document.createElement('a');
|
||
|
link.download = 'gradient-bands.png';
|
||
|
link.href = canvas.toDataURL();
|
||
|
link.click();
|
||
|
}
|
||
|
|
||
|
function initializeEventListeners() {
|
||
|
document.getElementById('start-color').addEventListener('input', renderGradient);
|
||
|
document.getElementById('end-color').addEventListener('input', renderGradient);
|
||
|
document.getElementById('bands').addEventListener('input', renderGradient);
|
||
|
document.getElementById('func').addEventListener('input', renderGradient);
|
||
|
document.getElementById('download-btn').addEventListener('click', downloadCanvas);
|
||
|
}
|
||
|
|
||
|
document.addEventListener('DOMContentLoaded', () => {
|
||
|
initializeEventListeners();
|
||
|
renderGradient();
|
||
|
});
|