Знаете что это внезапная внезапность? Рандомайзер цвета в формате рулетки!
https://codepen.io/borntofrappe/pen/zyLoJR
[html] <style> /* import font(s) */ @import url("https://fonts.googleapis.com/css?family=Alegreya+Sans+SC:400,900"); /* detail root variables --color-theme cascades to most html elements, and will be later updated in JavaScript */ :root { --font: "Alegreya Sans SC", sans-serif; --color-bg: #000b14; --color-theme: #70a9fe; } /* heading centered atop the page */ h17 { text-align: center; margin: 1rem 0 0; font-size: 3rem; transition: all 0.25s ease-in-out; display: block; position: absolute; right: 110px; top: 160px; border: 3px solid currentColor; padding: 10px; background: #fff; color: var(--color-theme); } /* shown/hidden through an dedicated class */ h17.isHidden { opacity: 0; visibility: hidden; transform: translateY(-1rem) scale(0); } /* wheel positioned to the left of the page, and occupying 50% of whichever dimension is the biggest */ svg#wheel { position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 500px; height: 500px; } /* arrow positioned to the right of the wheel, and pointing at the very middle section */ svg#pin { position: absolute; left: 500px; width: calc(50vmax / 25); height: calc(50vmax / 25); top: 50%; transform: translateY(-50%); fill: var(--color-theme); } /* instructions displayed on the right side, in a single column layout */ .instructions { min-height: 600px; color: var(--color-theme); display: flex; flex-direction: column; align-items: flex-end; justify-content: center; padding: 1rem; } .instructions h2 { font-size: 1rem; letter-spacing: 0.1rem; position: relative; } /* beside a silly exclamation point add a simple word in the middle of the sentence hinting at the innocent nature of the project */ .instructions h2:after { content: "!"; } .instructions h2:before { position: absolute; content: "suspicious"; font-size: 0.75rem; opacity: 0.6; bottom: 100%; left: 50%; transform: translateX(-50%) rotate(-12deg); } .instructions button { margin-top: 1rem; padding: 0.25rem 0.75rem; font-size: 1.55rem; font-family: inherit; color: inherit; border: none; border-radius: 10px; box-shadow: 0 0 0 2px currentColor; background: var(--color-bg); /* transition for a simple hover and active state */ transition: all 0.5s ease-out; } .instructions button:hover { box-shadow: 0 0 0 1px var(--color-bg), 0 0 0 3px currentColor, 0 0 0 5px var(--color-bg), 0 0 0 7px currentColor; } .instructions button:active { box-shadow: 0 0 0 2px currentColor, 0 0 0 4px var(--color-bg), 0 0 0 6px currentColor; transform: scale(0.95) translateY(0.1rem); } /* cursor customized to grab, and not allowed when the wheel is spinning (class added in JS) */ .instructions button, svg#pin { cursor: grab; } .instructions button.isSpinning, svg#pin.isSpinning { cursor: not-allowed; } /* animation for the pin, to have it soundly move up and down alongside the spinning wheel the duration of the animation is customized in JS to have it run a certain number of times */ @keyframes pinWheel { 33% { transform: translateY(-50%) rotate(-10deg); } 67% { transform: translateY(-50%) rotate(10deg); } } </style> <script> // target the SVG and the pin right next to it const containerSlices = document.querySelector('g#slices'); const pin = document.querySelector('svg#pin'); // immediately add simple dots around the wheel for (let i = 0; i < 48; i += 1) { const transform = `rotate(${360 / 48 * i}), translate(0 -49.5), rotate(${-360 / 48 * i})`; const dot = `<circle r="0.5" cx="50" cy="50" fill="currentColor" transform="${transform}"/>`; containerSlices.innerHTML += dot; } // target the heading and the button const heading = document.querySelector('h17'); const spinButton = document.querySelector('button'); // variable updated for the timeout let timeoutID = 0; // utility functions returning a random integer in a range and a random hex value const randomInt = (min = 0, max = 16) => Math.floor(Math.random() * (max - min) + min); const randomHex = () => randomInt().toString(16); // object used throughout the script, describing the colors and 3 particular rotation values // the idea is to include the three slices aroud the wheel and have the arrow point always at one of them const suspicious = [ { rotation: 45, color: 'A2CCB6' }, { rotation: 180, color: 'FCEEB5' }, { rotation: 315, color: 'EE786E' } ]; // add a random fill color to the circle behind the slices let randomFill = ''; for (let i = 0; i < 6; i += 1) { randomFill += randomHex(); } document.querySelector('svg circle#slice').style.fill = randomFill; // create the slices, 24 in total, using a bit of trigonometry to compute the appropriate arc coordinates for (let i = 360; i > 0; i -= 15) { // values for the path element const xCoor = 50 + Math.sin(i * Math.PI / 180) * 47; const yCoor = 50 - Math.cos(i * Math.PI / 180) * 47; const flags = i > 180 ? '0 1 1' : '0 0 1'; // initialize a variable for the fill color let fill = ''; // create six random hex values for the fill color // ! the look might be rather jarring for (let j = 0; j < 6; j += 1) { fill += randomHex(); } // if the de-cremented variable matches the arbitrary rotation value of one of the objects, find the specific object const suspect = suspicious.find(pairing => pairing.rotation === i); // if existing, substitute the random hex with the value specified in said object if (suspect) { fill = suspect.color; } // create the path element and append it to the SVG container const path = ` <path d="M 50 50 L 50 3 A 47 47 ${flags} ${xCoor} ${yCoor}" fill=#${fill} /> `; containerSlices.innerHTML += path; } // function spinning the wheel function spinWheel() { // remove the event listener from the button and the wheel, to avoid running the function twice at the same time spinButton.removeEventListener('click', spinWheel); pin.removeEventListener('click', spinWheel); // immediately hide the heading showing the matching color heading.classList.add('isHidden'); // add a class to the pin and the button to show how they should not be clicked pin.classList.add('isSpinning'); spinButton.classList.add('isSpinning'); // create variables for the duration of the rotation, as whell as the number of rotations achieved by the wheel const randomDuration = randomInt(4, 10); const randomRotate = randomInt(10, 20); // crate a variable to pick from one of the objects at random const randomSuspect = randomInt(0, 3); // apply the transition and the transform properties containerSlices.style.transformOrigin = '50%'; containerSlices.style.transition = `transform ${randomDuration}s ease-out`; /* for the rotation, beside an arbitrary x360 rotation, remember to - add 90 to match the position of the arrow (to the very right of the wheel) - subtract the rotation of the slices - add up to a slice as to have the arrow point within the slice's boundaries */ containerSlices.style.transform = `rotate(${randomRotate * 360 - suspicious[randomSuspect].rotation + 90 + randomInt(0, 360 / 24)}deg)`; pin.style.animation = `pinWheel ${randomDuration / 10}s 10 ease-in-out`; // after the time allocated for the rotation show the heading with the "random" color, update the custom property with its value timeoutID = setTimeout(() => { heading.textContent = `#${suspicious[randomSuspect].color}`; heading.classList.remove('isHidden'); pin.style.animation = ''; document.documentElement.style.setProperty('--color-theme', `#${suspicious[randomSuspect].color}`); // remove the class on the pin and button showing the forbidden cursor pin.classList.remove('isSpinning'); spinButton.classList.remove('isSpinning'); // reset the event listener on the button and the pin spinButton.addEventListener('click', spinWheel); pin.addEventListener('click', spinWheel); // clear the interval and set the boolean back to false clearInterval(timeoutID); }, randomDuration * 1000); } // attach a click event listener on the button, at which point call the spinWheel function spinButton.addEventListener('click', spinWheel); // call the same function when pressing the pin pin.addEventListener('click', spinWheel); </script> <!-- project's structure - svg for the color wheel (consisting of circle elements, and a group in which the slices are added) - svg for the arrow pointing at the selected color (positioned to the right of the circle) - heading in which to show the color selected through the wheel (hidden by default) - container for the simple instructions and the button spinning the wheel --> <svg id="wheel" viewBox="0 0 100 100"> <circle cx="50" cy="50" r="48" fill="none" stroke-width="1" stroke="currentColor" /> <!-- add an id to the underlying circle as this depicts the final slice, and as to add a random color --> <circle id="slice" cx="50" cy="50" r="47" fill="#001C34" /> <g id="slices"></g> </svg> <svg id="pin" viewBox="0 0 50 50"><path d="M 0 25 L 50 0 V 50" /></svg> <h17 class="isHidden" style="user-select: all;">#ffffff00</h17> <div class="instructions"> <h2>Spin that color <span>wheel</span></h2> <button>Spin!</button> </div> [/html]