Color Layer Mixer

Dynamically creates clones and removes layers with custom colors

by Michał Oręziak

HTML

<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css">
<button id="add" class="btn btn-primary">
  Add layer
</button>
<div id="contextMenu">
  <div class="list-group">
    <div class="list-group-item">
      <label>R</label>
      <input type="range" min="0" max="255" id="r">
    </div>
    <div class="list-group-item">
      <label>G</label>
      <input type="range" min="0" max="255" id="g">
    </div>
    <div class="list-group-item">
      <label>B</label>
      <input type="range" min="0" max="255" id="b">
    </div>
    <div class="list-group-item">
      <label>A</label>
      <input type="range" min="0" max="100" id="a">
    </div>
    <div class="list-group-item">
      <div class="input-group">
        <input type="number" class="form-control" placeholder="z-index" id="zIndex" aria-describedby="basic-addon1">
      </div>
    </div>
    <button type="button" class="list-group-item list-group-item-action clone">Clone</button>
    <button type="button" class="list-group-item list-group-item-action remove">Remove</button>
  </div>
</div>

CSS

#add {
  position: absolute;
  top: 10px;
  right: 10px;
}

#contextMenu {
  position: absolute;
  display: none;
  z-index: 10000;
  background: #fff;
}

.layer {
  display: none;
  height: 100px;
  width: 100px;
  float: left;
  margin-left: 5px;
  border-radius: 50%;
  background: #f00;
  z-index: 0;
}

JavaScript

let target;

function createLayer(clone) {
  let newLayer = $(document.createElement('div'))
    .attr('class', 'layer')
    .draggable({
      drag: function() {
        $('#contextMenu').fadeOut();
      }
    })
    .resizable({
      aspectRatio: 1 / 1,
      resize: function() {
        $('#contextMenu').fadeOut();
      }
    })
    .contextmenu(showMenu);

  if (clone === true) {
    newLayer.css('background-color', $(target).css('background-color'));
    newLayer.css('zIndex', $(target).css('zIndex'));
    newLayer.css('width', $(target).css('width'));
    newLayer.css('height', $(target).css('height'));
  }

  $('body').append(newLayer);
  newLayer.fadeIn();
}

function changeCss() {
  $(target).css('background', 'rgba(' + $('#r').val() + ',' + $('#g').val() + ',' + $('#b').val() + ',' + $('#a').val() / 100 + ')');
  $(target).css('zIndex', $('#zIndex').val());
}

function showMenu(ev) {
  ev.preventDefault();
  $('#contextMenu').css('left', ev.pageX);
  $('#contextMenu').css('top', ev.pageY);
  $('#contextMenu').fadeIn('fast');

  target = ev.target;
  getRGBA();



  function getRGBA() {
    var bg = $(ev.target).css('background-color');
    var rgb = bg.replace(/^(rgb|rgba)\(/, '').replace(/\)$/, '').replace(/\s/g, '').split(',');
    $('#contextMenu #r').val(rgb[0]);
    $('#contextMenu #g').val(rgb[1]);
    $('#contextMenu #b').val(rgb[2]);
    if (rgb.length == 3) {
      $('#contextMenu #a').val(100);
    } else {
      $('#contextMenu #a').val(rgb[4]);
    }
    $('#contextMenu #zIndex').val($(ev.target).css('zIndex'));
  }

}


$('#add').click(createLayer);
$('.remove').click(function() {
  $(target).remove();
  $('#contextMenu').fadeOut();
})
$('.clone').click(function() {
  createLayer(true);
  $('#contextMenu').fadeOut();
})
$(document).click(function(evt) {
  $('#contextMenu').fadeOut();
});
$('#contextMenu').click(function(event) {
  event.stopPropagation();
});

$('#contextMenu input').on('input', changeCss);