diff --git a/site/gradient-bands/index.html b/site/gradient-bands/index.html new file mode 100644 index 0000000..70b9471 --- /dev/null +++ b/site/gradient-bands/index.html @@ -0,0 +1,56 @@ + + + + + + Gradient Bands - Tools + + + + +
+
+

Gradient Bands

+

Generate colour gradients with customisable bands

+
+
+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+
+ + + + \ No newline at end of file diff --git a/site/gradient-bands/main.js b/site/gradient-bands/main.js new file mode 100644 index 0000000..d2fa76d --- /dev/null +++ b/site/gradient-bands/main.js @@ -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(); +}); \ No newline at end of file diff --git a/site/gradient-bands/style.css b/site/gradient-bands/style.css new file mode 100644 index 0000000..9d42d11 --- /dev/null +++ b/site/gradient-bands/style.css @@ -0,0 +1,4 @@ +canvas { + display: block; + margin-block-end: 12px; +} \ No newline at end of file diff --git a/site/index.html b/site/index.html index 3e33e42..f0756cc 100644 --- a/site/index.html +++ b/site/index.html @@ -22,6 +22,7 @@
  • Clocks
  • Freelens Logo Maker
  • Go Template Playground
  • +
  • Gradient Bands
  • Two-letter Country Codes