This commit is contained in:
parent
d1dee7bc3d
commit
f53aad9a94
56
site/gradient-bands/index.html
Normal file
56
site/gradient-bands/index.html
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Gradient Bands - Tools</title>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
|
||||||
|
>
|
||||||
|
<link rel="stylesheet" href="./style.css">
|
||||||
|
</head>
|
||||||
|
<body class="container">
|
||||||
|
<header>
|
||||||
|
<hgroup>
|
||||||
|
<h1>Gradient Bands</h1>
|
||||||
|
<p>Generate colour gradients with customisable bands</p>
|
||||||
|
</hgroup>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section>
|
||||||
|
<div class="grid">
|
||||||
|
<div>
|
||||||
|
<label for="start-color">Start Colour</label>
|
||||||
|
<input type="color" id="start-color" value="#ff0000">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="end-color">End Colour</label>
|
||||||
|
<input type="color" id="end-color" value="#0000ff">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="bands">Number of Bands</label>
|
||||||
|
<input type="number" id="bands" value="10" min="1" max="100">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="func">Function</label>
|
||||||
|
<select id="func">
|
||||||
|
<option value="linear">Linear</option>
|
||||||
|
<option value="quad">Quadratic</option>
|
||||||
|
<option value="cubic">Cubic</option>
|
||||||
|
<option value="sin">Sinusoidal</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<canvas id="gradient-canvas" width="800" height="400"></canvas>
|
||||||
|
<button id="download-btn">Download PNG</button>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="main.js" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
99
site/gradient-bands/main.js
Normal file
99
site/gradient-bands/main.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
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();
|
||||||
|
});
|
4
site/gradient-bands/style.css
Normal file
4
site/gradient-bands/style.css
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
canvas {
|
||||||
|
display: block;
|
||||||
|
margin-block-end: 12px;
|
||||||
|
}
|
|
@ -22,6 +22,7 @@
|
||||||
<li><a href="/clocks/">Clocks</a></li>
|
<li><a href="/clocks/">Clocks</a></li>
|
||||||
<li><a href="/freelens-logo/">Freelens Logo Maker</a></li>
|
<li><a href="/freelens-logo/">Freelens Logo Maker</a></li>
|
||||||
<li><a href="/gotemplate/">Go Template Playground</a></li>
|
<li><a href="/gotemplate/">Go Template Playground</a></li>
|
||||||
|
<li><a href="/gradient-bands/">Gradient Bands</a></li>
|
||||||
<li><a href="/2lcc/">Two-letter Country Codes</a></li>
|
<li><a href="/2lcc/">Two-letter Country Codes</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</main>
|
</main>
|
||||||
|
|
Loading…
Reference in a new issue