diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-02-20 16:11:50 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-02-20 16:15:08 +0100 |
| commit | 73a5c7fae9ffbe9ada721148c8c454a643aceebe (patch) | |
| tree | c8fad013ed9b5dd589add87f8d45cf02bbfc6e91 /public/projects/js-small-apps/color-cycle/app.js | |
| parent | b01239fbdcc5bbc5921f73ec0e8fee7bedd5c8e8 (diff) | |
chore!: restructure repo
I separated public files from the config/dev files. It improves repo
readability.
I also moved dotenv helper to public/inc directory and extract the
Matomo tracker in the same directory.
Diffstat (limited to 'public/projects/js-small-apps/color-cycle/app.js')
| -rw-r--r-- | public/projects/js-small-apps/color-cycle/app.js | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/public/projects/js-small-apps/color-cycle/app.js b/public/projects/js-small-apps/color-cycle/app.js new file mode 100644 index 0000000..2ed8e7f --- /dev/null +++ b/public/projects/js-small-apps/color-cycle/app.js @@ -0,0 +1,208 @@ +let isRunning = false; +let intervalId; + +/** + * Check if the provided value is a valid hexadecimal. + * @param {String} value - Two hexadecimal symbols. + * @returns {Boolean} True if value is a valid hexadecimal ; false otherwise. + */ +function isValidHex(value) { + const hexSymbols = "0123456789ABCDEF"; + const hexArray = value.split(""); + if (hexArray.length !== 2) return false; + if (!hexSymbols.includes(hexArray[0].toUpperCase())) return false; + if (!hexSymbols.includes(hexArray[1].toUpperCase())) return false; + return true; +} + +/** + * Print a message to notify user. + * @param {String} msg A message to print. + */ +function notify(msg) { + const body = document.querySelector(".body"); + const notification = document.createElement("div"); + notification.classList.add("notification"); + notification.textContent = msg; + body.appendChild(notification); + + setTimeout(() => { + notification.remove(); + }, 3000); +} + +/** + * Check if colors are set and are valid hexadecimal. + * @param {String} red - Hexadecimal string for red color. + * @param {String} green - Hexadecimal string for green color. + * @param {String} blue - Hexadecimal string for blue color. + * @returns {Boolean} True if colors are ready; false otherwise. + */ +function areColorsReady(red, green, blue) { + if (!red || !green || !blue) return false; + + if (!isValidHex(red)) { + notify("Red is not hexadecimal."); + return false; + } + + if (!isValidHex(green)) { + notify("Green is not hexadecimal."); + return false; + } + + if (!isValidHex(blue)) { + notify("Blue is not hexadecimal."); + return false; + } + + return true; +} + +/** + * Update the preview color with the provided color. + * @param {String} color - Hexadecimal string with a leading hash (CSS format). + */ +function updatePreviewColor(color) { + const preview = document.querySelector(".preview"); + preview.style.backgroundColor = color; +} + +/** + * Initialize the preview with user settings. + * @param {Object} ui - The different element corresponding to the user interface. + */ +function setPreview(ui) { + const red = ui.colors.red.value; + const green = ui.colors.green.value; + const blue = ui.colors.blue.value; + + if (areColorsReady(red, green, blue)) { + const currentColor = `#${red}${green}${blue}`; + updatePreviewColor(currentColor); + } +} + +/** + * Generate a new color. + * @param {Integer} color - An integer corresponding to a RGB value. + * @param {Integer} increment - Add this value to color argument. + */ +function* getColor(color, increment) { + let nextColor = color; + yield nextColor; + + while (true) { + if (nextColor + increment > 255) { + nextColor = nextColor - 255 + increment; + } else { + nextColor = nextColor + increment; + } + + yield nextColor; + } +} + +/** + * Convert an RGB color to hexadecimal format. + * @param {Integer} red - An integer representing red color with RGB format. + * @param {Integer} green - An integer representing green color with RGB format. + * @param {Integer} blue - A value representing blue color with RGB format. + * @returns {String} The color in hexadecimal format with a leading hash. + */ +function getNexHexColor(red, green, blue) { + return `#${red.toString(16)}${green.toString(16)}${blue.toString(16)}`; +} + +/** + * Disable or enable inputs. + * @param {Object} ui - The HTMLElements corresponding to user interface. + */ +function toggleInputs(ui) { + ui.colors.red.disabled = isRunning; + ui.colors.green.disabled = isRunning; + ui.colors.blue.disabled = isRunning; + ui.increments.red.disabled = isRunning; + ui.increments.green.disabled = isRunning; + ui.increments.blue.disabled = isRunning; + ui.interval.disabled = isRunning; +} + +/** + * Start or stop the preview. + * @param {Object} ui - The HTMLElements corresponding to user interface. + */ +function start(ui) { + const red = ui.colors.red.value; + const green = ui.colors.green.value; + const blue = ui.colors.blue.value; + + if (areColorsReady(red, green, blue)) { + isRunning = !isRunning; + ui.button.textContent = isRunning ? "Stop" : "Start"; + } else { + notify("Colors are not correctly set."); + } + + const redIncrement = Number(ui.increments.red.value); + const greenIncrement = Number(ui.increments.green.value); + const blueIncrement = Number(ui.increments.blue.value); + const redGenerator = getColor(parseInt(red, 16), redIncrement); + const greenGenerator = getColor(parseInt(green, 16), greenIncrement); + const blueGenerator = getColor(parseInt(blue, 16), blueIncrement); + const timing = ui.interval.value; + + if (isRunning) { + toggleInputs(ui); + intervalId = setInterval(() => { + const nextRed = redGenerator.next().value; + const nextGreen = greenGenerator.next().value; + const nextBlue = blueGenerator.next().value; + const newColor = getNexHexColor(nextRed, nextGreen, nextBlue); + updatePreviewColor(newColor); + }, timing); + } else { + toggleInputs(ui); + clearInterval(intervalId); + } +} + +/** + * Listen form, buttons and inputs. + * @param {Object} ui - The HTMLElements corresponding to user interface. + */ +function listen(ui) { + ui.form.addEventListener("submit", (e) => { + e.preventDefault(); + }); + ui.button.addEventListener("click", () => start(ui)); + ui.colors.red.addEventListener("change", () => setPreview(ui)); + ui.colors.green.addEventListener("change", () => setPreview(ui)); + ui.colors.blue.addEventListener("change", () => setPreview(ui)); +} + +/** + * Initialize the app. + */ +function init() { + const ui = { + button: document.querySelector(".btn"), + form: document.querySelector(".form"), + colors: { + red: document.getElementById("color-red"), + green: document.getElementById("color-green"), + blue: document.getElementById("color-blue"), + }, + increments: { + red: document.getElementById("increment-red"), + green: document.getElementById("increment-green"), + blue: document.getElementById("increment-blue"), + }, + interval: document.getElementById("time-interval"), + }; + + setPreview(ui); + listen(ui); +} + +init(); |
