2 687 Codepen

Генератор птиц

С помощью jаvascript генерируются летящие птицы с разным оперением, которые сами сделаны на чистом CSS


В демке с помощью шестеренки в углу можно вызвать панель для управления генерацией птиц.

HTML

<div class="stage">
  <button class="form-toggle settings-toggle">
    <svg version="1.1"  xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" >
      <path d="M23,13.4v-2.8l-3-0.8c-0.2-0.7-0.5-1.4-0.8-2l1.6-2.8l-1.9-1.9l-2.8,1.6c-0.6-0.4-1.3-0.7-2-0.8l-0.8-3h-2.8
               L9.9,4c-0.7,0.2-1.4,0.5-2,0.8L5.1,3.3L3.3,5.1l1.6,2.8C4.5,8.5,4.2,9.2,4,9.9l-3,0.8v2.8l3,0.8c0.2,0.7,0.5,1.4,0.8,2l-1.6,2.8
               l1.9,1.9l2.8-1.6c0.6,0.4,1.3,0.7,2,0.8l0.8,3h2.8l0.8-3c0.7-0.2,1.4-0.5,2-0.8l2.8,1.6l1.9-1.9l-1.6-2.8c0.4-0.6,0.7-1.3,0.8-2
               L23,13.4z M12,17c-2.8,0-5-2.2-5-5s2.2-5,5-5s5,2.2,5,5S14.8,17,12,17z"/>
    </svg>
  </button>
  <div class="settings-form hidden">
    <button class="form-toggle close-toggle">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
        <title>close-24x24</title>
        <g id="_24x24">
          <path d="M14.58,12l5.88-5.89a1.82,1.82,0,0,0-2.58-2.58L12,9.42,6.12,3.53A1.82,1.82,0,1,0,3.53,6.11L9.42,12,3.53,17.89a1.82,1.82,0,1,0,2.58,2.58L12,14.58l5.88,5.88a1.82,1.82,0,1,0,2.58-2.58Z"/>
        </g>
      </svg>
    </button>
    <div class="form-field-group">
      <label>Spawn Rate</label>
      <span>Slow</span>
      <input class="inverted" type="range" min="50" max="2000" value="1000" data-name="spawnRate"/>
      <span>Fast</span>
    </div>
    <div class="form-field-group">
      <label>Flight Speed</label>
      <span>Slow</span>
      <input class="inverted" type="range" min="1" max="5" value="3" data-name="durationMultiple"/>
      <span>Fast</span>
    </div>  
  </div>
</div>

CSS

html, body {
  width: 100%;
  overflow: hidden;
  box-sizing: border-box;
}

.stage {
  display: flex;
  align-items: center;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  overflow: visible;
  background: linear-gradient(#69FFC5, #69fff7);
  box-sizing: border-box;
}

.birb-container {
  position: absolute;
  top: 50%;
  right: 100%;
  transform-origin: left center;
  animation: fly-by 2000ms linear;
}

.birb {
  position: relative;
  display: block;
  width: 20vw;
  height: 20vw;
  animation: infinite altitude-variance 500ms ease;
}

.body {
  position: absolute;
  left: 0;
  top: 20%;
  width: 70%;
  height: 40%;
  border-bottom-right-radius: 50% 80%;
  border-bottom-left-radius: 50% 80%;
  box-shadow: inset -3vw -2vw 2vw rgba(0, 0, 20, 0.2);
  -webkit-backface-visibility: hidden;
}
.body:after {
  content: '';
  display: block;
  position: absolute;
  left: -10%;
  top: 35%;
  width: 30%;
  height: 30%;
  border-radius: 0 0 100% 0;
  background: linear-gradient(#f7c96e, #f7e06e);
}

.head-container {
  position: relative;
  left: 80%;
  top: 0;
  width: 50%;
  height: 80%;
  z-index: 1;
}

.head {
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 0 100% 100% 100%;
  box-shadow: inset -1vw -2vw 1vw rgba(0, 0, 10, 0.2);
  z-index: 1;
  -webkit-backface-visibility: hidden;
}
.head:before {
  content: '';
  display: block;
  position: absolute;
  left: 55%;
  top: 35%;
  width: 15%;
  height: 15%;
  border-radius: 100%;
  background: rgba(82, 20, 20, 0.2);
  z-index: 1;
}
.head:after {
  content: '';
  display: block;
  position: absolute;
  right: 10%;
  bottom: 25%;
  width: 50%;
  height: 50%;
  border-radius: 100%;
  background: rgba(255, 255, 255, 0.25);
  z-index: 2;
  -webkit-backface-visibility: hidden;
}

.beak {
  position: absolute;
  left: 80%;
  top: 20%;
  width: 50%;
  height: 70%;
  background: #f7e06e;
  box-shadow: inset -1vw -2vw 1vw #f7f76e;
  border-radius: 0 100% 0 0;
  z-index: -2;
}
.beak:after {
  content: '';
  display: block;
  position: absolute;
  left: -50%;
  top: 100%;
  width: 100%;
  height: 20%;
  border-radius: 0 0 100% 0;
  background: #f7c96e;
  z-index: -1;
  -webkit-backface-visibility: hidden;
}

.wing-front {
  position: absolute;
  width: 60%;
  height: 180%;
  top: 0;
  left: 25%;
  transform-origin: top center;
  border-radius: 0 0 100% 10%;
  animation: infinite wing-front-flap 300ms ease;
  z-index: 1;
}

.wing-back {
  z-index: -2;
  position: absolute;
  width: 40%;
  height: 130%;
  top: 0;
  left: 60%;
  transform-origin: top center;
  border-radius: 0 0 100% 10%;
  animation: infinite wing-back-flap 300ms ease;
}

.tail {
  position: absolute;
  top: 0%;
  right: 90%;
  height: 35%;
  width: 100%;
  border-bottom-left-radius: 100% 100%;
  transform: rotate(3deg);
  transform-origin: top right;
}

@keyframes fly-by {
  50% {
    opacity: 1;
  }
  100% {
    transform: translate(120vw, -30vh);
    opacity: .1;
  }
}
@keyframes altitude-variance {
  50% {
    transform: translate(0, 6%);
  }
}
@keyframes wing-front-flap {
  0%,100% {
    transform: rotateX(10deg);
  }
  50% {
    transform: rotateX(140deg);
  }
}
@keyframes wing-back-flap {
  0%,100% {
    transform: rotateX(0deg);
  }
  50% {
    transform: rotateX(-120deg);
  }
}
.form-toggle {
  display: block;
  box-sizing: border-box;
  border: none;
  appearance: none;
  padding: .5rem;
  height: 2.5rem;
  cursor: pointer;
  background: none;
  text-transform: uppercase;
  font-family: 'Montserrat', sans-serif;
  font-weight: 600;
  color: #009c94;
  border-radius: 4px;
  letter-spacing: .1em;
  fill: #009c94;
  z-index: 2;
  overflow: auto;
}

.settings-toggle {
  position: absolute;
  bottom: .5rem;
  right: .5rem;
}

.close-toggle {
  position: absolute;
  top: 0;
  right: 0;
}

.settings-form {
  position: absolute;
  right: .5rem;
  bottom: 0;
  left: .5rem;
  z-index: 3;
  background: rgba(255, 255, 255, 0.9);
  padding: 2rem 1rem;
  box-sizing: border-box;
  position: absolute;
  border-radius: 4px 4px 0 0;
  transition: all 300ms ease;
  font-family: 'Montserrat', sans-serif;
  letter-spacing: .1em;
  font-size: 1rem;
  box-shadow: 0 4px 4px rgba(255, 255, 255, 0.25);
}
.settings-form.hidden {
  transform: translateY(100%);
}

.form-field-group {
  white-space: nowrap;
  display: flex;
  flex-wrap: wrap;
  margin-bottom: .5rem;
  max-width: 40rem;
  margin: 0 auto 1rem;
  text-transform: uppercase;
  user-select: none;
}
.form-field-group label {
  display: block;
  width: 100%;
  text-align: center;
  margin-bottom: .5rem;
  color: #009c94;
}
.form-field-group input {
  display: block;
  flex-grow: 1;
}
.form-field-group input.inverted {
  transform: rotate(180deg);
}
.form-field-group span {
  width: 4rem;
  flex-shrink: 0;
  text-align: center;
  font-size: .75rem;
  color: #009c94;
}

JS

// Settings and controls

var settings = {
  spawnRate: 1000, // ms
  minAnimationDuration: 400, // ms
  maxAnimationDuration: 1000, // ms
  durationMultiple: 3,
  minSize: 5, // vw
  maxSize: 25, // vw
  saturation: 70, // %
  lightness: 75 // %
};

var updateSetting = function updateSetting(e) {
  var target = e.target;

  var settingName = target.getAttribute('data-name');
  settings[settingName] = parseInt(target.value);
  console.log(settings);
};

var toggleSettingsMenu = function toggleSettingsMenu() {
  var settingsMenu = document.querySelector('.settings-form');
  settingsMenu.classList.contains('hidden') ? settingsMenu.classList.remove('hidden') : settingsMenu.classList.add('hidden');
};

var settingsToggle = document.querySelector('.settings-toggle');
settingsToggle.addEventListener('click', toggleSettingsMenu, false);

var closeToggle = document.querySelector('.close-toggle');
closeToggle.addEventListener('click', toggleSettingsMenu, false);

var inputs = document.querySelectorAll('input');

for (var i = 0; i < inputs.length; i++) {if (window.CP.shouldStopExecution(1)){break;}
  inputs[i].addEventListener('change', updateSetting, false);
}
window.CP.exitedLoop(1);


// Helper functions

var getRandomHslColorObject = function getRandomHslColorObject() {
  var colorObject = {
    h: getRandomNumberInRange(0, 360),
    s: settings.saturation,
    l: settings.lightness
  };

  return colorObject;
};

var getRandomNumberInRange = function getRandomNumberInRange() {
  var min = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  var max = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100;

  return '' + (Math.floor(Math.random() * (max - min)) + min);
};

// Birb stuff

var removeBirb = function removeBirb(e) {
  var birb = e.target;
  birb.parentElement.removeChild(birb);
};

var createBirb = function createBirb() {
  var color = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { h: 100, s: 60, l: 100 };


  var birbSize = getRandomNumberInRange(settings.minSize, settings.maxSize) + 'vw';

  var birbContainer = document.createElement('div');
  birbContainer.classList.add('birb-container');
  birbContainer.style.top = getRandomNumberInRange(0, 100) + '%';
  birbContainer.style.animationDuration = getRandomNumberInRange(settings.minAnimationDuration * settings.durationMultiple, settings.maxAnimationDuration * settings.durationMultiple) + 'ms';
  birbContainer.addEventListener('animationend', removeBirb, false);

  var birb = document.createElement('div');
  birb.classList.add('birb');
  birb.style.height = birbSize;
  birb.style.width = birbSize;
  birbContainer.appendChild(birb);

  var body = document.createElement('div');
  body.classList.add('body');
  body.style.backgroundColor = 'hsl(' + color.h + ', ' + color.s + '%, ' + color.l + '%)';
  birb.appendChild(body);

  var headContainer = document.createElement('div');
  headContainer.classList.add('head-container');
  body.appendChild(headContainer);

  var head = document.createElement('div');
  head.classList.add('head');
  head.style.backgroundColor = 'hsl(' + (color.h + 90) + ', ' + color.s + '%, ' + color.l + '%)';
  headContainer.appendChild(head);

  var beak = document.createElement('div');
  beak.classList.add('beak');
  headContainer.appendChild(beak);

  var wingFront = document.createElement('div');
  wingFront.classList.add('wing-front');
  wingFront.style.backgroundColor = 'hsl(' + color.h + ', ' + color.s + '%, ' + (color.l - 10) + '%)';
  body.appendChild(wingFront);

  var wingBack = document.createElement('div');
  wingBack.classList.add('wing-back');
  wingBack.style.backgroundColor = 'hsl(' + color.h + ', ' + color.s + '%, ' + (color.l - 20) + '%)';
  body.prepend(wingBack);

  var tail = document.createElement('div');
  tail.classList.add('tail');
  tail.style.backgroundColor = 'hsl(' + color.h + ', ' + color.s + '%, ' + color.l + '%)';
  body.appendChild(tail);

  return birbContainer;
};

var makeBirbs = function makeBirbs() {
  var birdCount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;

  for (var i = 0; i < birdCount; i++) {if (window.CP.shouldStopExecution(2)){break;}
    var birbColorObject = getRandomHslColorObject();
    var birbContainer = createBirb(birbColorObject);
    var targetElement = document.querySelector('.stage');
    targetElement.appendChild(birbContainer);
  }
window.CP.exitedLoop(2);


  setTimeout(makeBirbs, settings.spawnRate);
};

//Init stuff
makeBirbs();

Комментарии

  • Facebook
  • Вконтакте

Похожие статьи