canvas#canvas

h1.title Random Palette Generator

label(for='rotate').rotate-label Rotate hue (bottom two rows):

input#rotate(type='number',value='90',min='15',max='360')

- var i = 1
- var n = 1
while i < 4
  .palette
    - var j = 1
    while j < 4
      .single
        div(id= 'color' + n++)
        .hex
      - j++
  - i++

p.instructions Hit [<kbd class="key1">Space</kbd>] for a new palette<br>Hit [<kbd class="key2">e</kbd>] to toggle background color
View Compiled
body {
  background: #131720;
  color: #fefefe;
  font: 300 1.625em/1.5 'Source Sans Pro', sans-serif;
  letter-spacing: 0.05em;
  text-align: center;
  padding: 2.5em 0 0;
}

kbd {
  font: inherit;
}

#canvas {
  margin: 0 auto;
}

.title {
  font-weight: 300;
  letter-spacing: 0;
  margin: 0.5em 0 0;
}

.color-label {
  padding-left: 1em;
}

#rotate {
  background: transparent;
  border: 0;
  font: inherit;
  margin-bottom: 2em;
  text-align: right;
  width: 2.5em;

  &:focus {
    outline: 1px solid;
  }
  
  /*
      Spinner input styling in Chrome
      https://css-tricks.com/snippets/css/turn-off-number-input-spinners/#comment-534949
  */
  
  &::-webkit-inner-spin-button {
    -webkit-appearance: none;
    cursor:pointer;
    margin-right: 8px;
    position:relative;
    width: 16px;
    
    &::before,
    &::after {
      content: "^";
      font-family: monospace;
      position: absolute;
      right: 0;
    }
    
    &::before {
      top: 0;
    }
    
    &::after {
      right: 1px;
      bottom: 0;
      transform: rotate(180deg);
    }
  }
}

.palette {
  margin: 0em auto;
  overflow: hidden;
  max-width: 100%;
  width: 15em;
}

.single {
  float: left;
  overflow: hidden;
  width: 33%;
}

.hex {
  display: block;
  font-size: 0.75em;
}


[id^=color] {
  border-radius: 100%;
  box-sizing: border-box;
  margin: 0.25em;
  position: relative;
  width: 4.5em;
  height: 4.5em;
}

.instructions {
  margin-top: 2em;
}

body.lightBackground {
    background: #fcfcfc;
    color: #131720;
    font-weight: 400;
}

.lightBackground .title {
    font-weight: 400;
}
View Compiled
/*
 a mess
*/

(function() {
  "use strict";

  /* Create the color palette on canvas */

  // Color variables
  var rotation, baseColor, secondColor, thirdColor, lightBackground;

  // Canvas variables
  var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    canvasWidth, canvasHeight;

  // Set canvas size
  canvasWidth = canvas.width = 80;
  canvasHeight = canvas.height = 80;

  // Helper functions
  var getRotation = function() {
    var r = document.getElementById('rotate').value;
    rotation = parseInt(r, 10);
  }

  var randomNum = function(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  };

  // Here come the colors
  var Color = function(hue, sat, light) {
    // Settings
    // Play with these to change the types of colors generated
    this.minHue = 0;
    this.maxHue = 360;

    this.minSat = 75;
    this.maxSat = 100;

    this.minLight = 65;
    this.maxLight = 80;

    this.scaleLight = 15;

    // Darker colors for a light background
    if (lightBackground) {
      this.minLight = 40;
      this.maxLight = 65;
    }

    // Set hue
    this.hue = hue || randomNum(this.minHue, this.maxHue);

    // Redo if ugly hue is generated
    // Because magenta is hideous
    if (this.hue > 288 && this.hue < 316) {
      this.hue = randomNum(316, 360);
    } else if (this.hue > 280 && this.hue < 288) {
      this.hue = randomNum(260, 280);
    }

    this.sat = sat || randomNum(this.minSat, this.maxSat);
    this.light = light || randomNum(this.minLight, this.maxLight);

    this.hsl = 'hsl(' + this.hue + ', ' + this.sat + '%, ' + this.light + '%)';
  };

  // Change hue by rotation number
  Color.prototype.changeHue = function(hue, rotate) {
    return hue + rotate > this.maxHue ?
      (hue + rotate) - this.maxHue : hue + rotate;
  };

  // Scale lightness while keeping within limits
  Color.prototype.changeLight = function(light) {
    return light + this.scaleLight > this.maxLight ? this.maxLight : light + this.scaleLight;
  };

  // Now generate the three main colors of the palette
  var setColors = function(newPalette) {
    if (newPalette) {
      baseColor = new Color();
    }

    secondColor = new Color(
      baseColor.changeHue(baseColor.hue, rotation),
      baseColor.sat,
      baseColor.changeLight(baseColor.light));

    thirdColor = new Color(
      baseColor.changeHue(baseColor.hue, rotation + rotation),
      baseColor.sat,
      baseColor.changeLight(baseColor.light));
  };

  // Draw colors on canvas
  var drawColor = function(x, y, width, height, color, blendMode, alpha) {
    ctx.save();
    ctx.beginPath();
    ctx.fillStyle = color;
    ctx.globalAlpha = alpha || 1;
    ctx.globalCompositeOperation = blendMode || 'source-over';
    ctx.rect(x, y, width, height);
    ctx.fill();
    ctx.closePath();
    ctx.restore();
  };

  // Draw the canvas
  var drawCanvas = function() {

    // Top color
    drawColor(0, 0, canvasWidth, canvasHeight, baseColor.hsl);

    // Middle color
    drawColor(0, canvasHeight / 3, canvasWidth, canvasHeight, secondColor.hsl);

    // Bottom color
    drawColor(0, canvasHeight / 3 + canvasHeight / 3, canvasWidth, canvasHeight, thirdColor.hsl);

    // Left color overlay (lightens with yellow)
    drawColor(0, 0, canvasWidth / 3, canvasHeight, '#fcd108', 'screen', 0.75);

    // Right color overlay (darkens with blue)
    drawColor(canvasWidth / 3 + canvasWidth / 3, 0, canvasWidth / 3, canvasHeight, '#094078', 'overlay');

    // Full color overlays (creates a cast over all colors for a more uniform, moderated look)
    drawColor(0, 0, canvasWidth, canvasHeight, '#ffcc00', 'overlay', 0.25);
    drawColor(0, 0, canvasWidth, canvasHeight, '#f13a6d', 'lighten', 0.25);
    drawColor(0, 0, canvasWidth, canvasHeight, '#092559', 'screen', 0.5);
  };

  /* Import the color palette to DOM */

  // Pick a color from canvas
  var getColor = function(x, y) {
    var rgba = ctx.getImageData(x, y, 1, 1).data;
    rgba[3] = 1; // set alpha channel from 255 to 1

    return rgba;
  };

  // Convert rgba array to hex
  var rgbToHex = function(rgb) {
    var hex = [];

    for (var i = 0; i < rgb.length - 1; i++) {
      hex[i] = rgb[i].toString(16);

      if (hex[i].length < 2) {
        hex[i] = '0' + hex[i]; // Pad with leading zero
      }
    }

    return '#' + hex.join('');
  };

  // Change text color of HTML element
  var changeElementColor = function(element, color) {
    document.querySelector(element).style.color = 'rgba(' + color.join(',') + ')';
  };

  // Now get all nine colors from canvas
  var createPalette = function() {
    var allColors = {
      c1: getColor(10, 10),
      c2: getColor(canvasWidth / 2 + 10, 0 + 10),
      c3: getColor(canvasWidth - 10, 0),

      c4: getColor(10, canvasHeight / 2 + 10),
      c5: getColor(canvasWidth / 2 + 10, canvasHeight / 2 + 10),
      c6: getColor(canvasWidth - 10, canvasHeight / 2),

      c7: getColor(10, canvasHeight - 10),
      c8: getColor(canvasWidth / 2 + 10, canvasHeight - 10),
      c9: getColor(canvasWidth - 10, canvasHeight - 10)
    };

    // And apply them to the DOM
    for (var i = 1; i < 10; i++) {
      document.getElementById('color' + i).style.backgroundColor = 'rgba(' + allColors['c' + i].join(',') + ')';
      document.querySelectorAll('.hex')[i - 1].style.color = 'rgba(' + allColors['c' + i].join(',') + ')';
      document.querySelectorAll('.hex')[i - 1].textContent = rgbToHex(allColors['c' + i]);
    }

    // And apply them to the text colors
    changeElementColor('.title', allColors.c2);
    changeElementColor('.rotate-label', allColors.c5);
    changeElementColor('#rotate', allColors.c8);

    changeElementColor('.instructions', allColors.c6);
    changeElementColor('.key1', allColors.c9);
    changeElementColor('.key2', allColors.c9);
  };

  // Run all the palette functions
  var init = function(newPalette) {
    getRotation();
    setColors(newPalette);
    drawCanvas();
    createPalette();
  };

  init('uhuh');

  /* Event listeners */

  // Input number box
  document.getElementById('rotate').addEventListener('input', function() {
    init();
  }, false);

  // Spacebar
  window.addEventListener('keydown', function(e) {
    if (e.keyCode === 32) {
      init('yehp');
      e.preventDefault();
    }
  }, false);

  window.addEventListener('keydown', function(e) {
    if (e.keyCode === 69) {
      lightBackground ? lightBackground = false : lightBackground = true;
      document.body.classList.toggle('lightBackground');

      e.preventDefault();
    }
  }, false);

}());

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.