block by dribnet 94327e00769397284a442537b68aaec0

MDDN242 Assignment 3: Glyph

Full Screen

PS3 MDDN 242 2018

Color Glyphs

Describe your black and white shapes that are meant to represent the colors above them (replacing this text). Be sure to use complete sentences, and you can reference your image above. The explanation should be short but compete, roughly 100 words.

Also update both images keeping their original sizes: preview.jpg (960x500) and thumbnail.png (230x120).

index.html

<head>
    <script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.dom.js"></script>
    <script src="z_hsluv-0.0.3.min.js"  type="text/javascript"></script>
    <script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
    <script language="javascript" type="text/javascript" src="z_color_helper.js"></script>
    <script language="javascript" type="text/javascript" src="glyph.js"></script>
    <script language="javascript" type="text/javascript" src="sketch.js"></script>
    <style>
        body   { padding: 0; margin: 0; }
        .inner { position: absolute; }
        #controls {
            font: 300 12px "Helvetica Neue";
            padding: 5;
            margin: 5;
            background: #f0f0f0;
            opacity: 0.0;
            -webkit-transition: opacity 0.2s ease;
            -moz-transition: opacity 0.2s ease;
            -o-transition: opacity 0.2s ease;
            -ms-transition: opacity 0.2s ease;
        }
        #controls:hover { opacity: 0.9; }
    </style>
</head>
<body style="background-color:white">
    <div class="outer">
        <div class="inner">
            <div id="canvasContainer"></div>
        </div>
        <div class="inner" id="controls" height="500px">
            <table>
                <tr>
                    <td>Hue</td>
                    <td id="slider1Container"></td>
                </tr>
                <tr>
                    <td>Saturation</td>
                    <td id="slider2Container"></td>
                </tr>
                <tr>
                    <td>Lightness</td>
                    <td id="slider3Container"></td>
                </tr>
                <tr>
                    <td>
                        <hr>
                    </td>
                </tr>
                <tr>
                    <td>Mode</td>
                    <td id="selector1Container"></td>
                </tr>
                <tr>
                    <td>Size</td>
                    <td id="selector3Container"></td>
                </tr>
                <tr>
                    <td>Display</td>
                    <td id="selector2Container"></td>
                </tr>
                <tr>
                    <td>Show Guide</td>
                    <td id="checkContainer"></td>
                </tr>
                <tr>
                    <td></td>
                    <td id="buttonContainer"></td>
                </tr>
        </div>
    </div>
</table>
</body>

glyph.js

/* change default application behavior */
var defaultMode = "sketch";
var defaultSize = 128;
var defaultDisplay = "both"
var defaultEmoji = 100;
var backgroundColor = "hsb(0, 0%, 94%)";

function Glyph() {
  /*
   * values is an array of 3 numbers: [hue, saturation, lightness]
   *   + hue ranges from 0..360
   *   + saturation ranges from 0..100
   *   + lightness ranges from 0..100
   *
   * size is the number of pixels for width and height
   *
   * use p5.js to draw a round grayscale glyph
   * the glyph should stay within the ellipse [0, 0, width, height]
   * this is a grayscale glyph, so only lightness can be adjusted.
   * the range for lightness is 0..100
   *
   * When setting the lightness of stroke or fill always use either strokeUniform()
   * or fillUniform() calls. Each takes one arguement - the lightness from
   * 0 to 100. Examples:
   *       - fillUniform(50);    // ranges from 0-100
   *       - strokeUniform(100); // white
   */ 
  this.draw = function(values, size) {
    // replace this with your own version

    // map lightness to large circle shade
    let color1 = map(values[2], 0, 100, 10, 70)
    strokeUniform(color1);
    fillUniform(color1)
    let s2 = size/2;
    ellipse(s2, s2, size);

    // inner size is set to 30%
    let inner_size = 0.2 + 0.4 * 0.3;
    let s3 = size * inner_size;

    // inner color based on saturation
    let color2 = map(values[1], 0, 100, color1+20, 240)
    fillUniform(color2);
    strokeUniform(color2);

    // hue controls left/right shift
    let shift_frac = (values[0] - 180.0) / 180.0;
    let max_shift = 0.5 * (size - s3);
    let x_shift = shift_frac * max_shift;
    ellipse(s2 + x_shift, s2, s3);  
  }  
}

purview.json

{
  "commits": [
    {
      "sha": "741659ce99f24eafa34c93e3973750eb54623250",
      "name": "final example: (double spinner)"
    },
    {
      "sha": "40acba7243a32d2d6b107dfc7ae61914eb8487e6",
      "name": "final example (spinner)"
    },
    {
      "sha": "906be590e037ccc57c608cf6725c2d0c712ee9e9",
      "name": "gradient example (spinner)"
    },
    {
      "sha": "83a0dd1aa6d94f9703d917d12e81ba93b6dea111",
      "name": "random example2: button"
    },
    {
      "sha": "b004b13c84f46572bff37901a0e4d7fe4f035ee0",
      "name": "random example1: spinner"
    },
    {
      "sha": "0b61a1a2e34cd5c5fecfde3fafec155fc6f7503e",
      "name": "sketch example"
    }
  ]
}

sketch.js


if (typeof defaultMode === 'undefined') {
  var defaultMode = "sketch";
}

if (typeof defaultSize === 'undefined') {
  var defaultSize = "128";
}

if (typeof defaultDisplay === 'undefined') {
  var defaultDisplay = "both";
}

if (typeof defaultEmoji === 'undefined') {
  var defaultDisplay = 76;
}

if (typeof backgroundColor === 'undefined') {
  var backgroundColor = "rgb(232, 232, 232)";
}


let canvasWidth = 960;
let canvasHeight = 500;

let glyphSelector;
let modeSelector;
let sizeSelector;
let show_oddball = false;
let oddball_row = 0;
let oddball_col = 0;

let val_sliders = [];
let max_vals = [360, 100, 100];

let curEmoji = defaultEmoji;
let NUM_EMOJI = 872;
let EMOJI_WIDTH = 38;

let lastKeyPressedTime;
let secondsUntilSwapMode = 10;
let secondsPerEmoji = 5;
let isSwappingEmoji = false;
let emojiSwapLerp = 0;
let prevEmoji = 0;
let lastEmojiSwappedTime;

let emojiImg;
let sketchImg;
let curEmojiImg;
let curEmojiPixels;
let curEmojiColors, nextEmojiColors, prevEmojiColors;
function preload() {
  emojiImg = loadImage("twemoji36b_montage.png");
  sketchImg = loadImage("sketch.png");
}

function setup() {
  // create the drawing canvas, save the canvas element
  let main_canvas = createCanvas(canvasWidth, canvasHeight);
  main_canvas.parent('canvasContainer');

  let now = millis();
  lastKeyPressedTime = now;
  lastEmojiSwappedTime = now;

  // create two sliders
  for (i=0; i<3; i++) {
    let slider = createSlider(0, 10*max_vals[i], 10*max_vals[i]/2);
    slider.parent("slider" + (i+1) + "Container")
    slider.changed(sliderUpdated);
    slider.mouseMoved(sliderUpdated);
    slider.touchMoved(sliderUpdated);
    val_sliders.push(slider);
  }

  modeSelector = createSelect();
  modeSelector.option('sketch');
  modeSelector.option('edit');
  modeSelector.option('random');
  modeSelector.option('gradient');
  modeSelector.option('oddball');
  modeSelector.option('image');
  modeSelector.changed(modeChangedEvent);
  modeSelector.value(defaultMode);
  modeSelector.parent('selector1Container');

  glyphSelector = createSelect();
  glyphSelector.option('color');
  glyphSelector.option('glyph');
  glyphSelector.option('both');
  glyphSelector.value(defaultDisplay);
  glyphSelector.parent('selector2Container');

  sizeSelector = createSelect();
  sizeSelector.option('32');
  sizeSelector.option('64');
  sizeSelector.option('128');
  sizeSelector.parent('selector3Container');
  sizeSelector.value(defaultSize);
  sizeSelector.changed(sizeChangedEvent);


  guideCheckbox = createCheckbox('', false);
  guideCheckbox.parent('checkContainer');
  guideCheckbox.changed(guideChangedEvent);

  button = createButton('redo');
  button.mousePressed(buttonPressedEvent);
  button.parent('buttonContainer');

  curEmojiImg = createImage(36, 36);
  // create an array for HSB values: [18][18][3]
  curEmojiPixels = Array(18);
  curEmojiColors = Array(18);
  for(let i=0; i<18; i++) {
    curEmojiPixels[i] = Array(18);
    curEmojiColors[i] = Array(18);
    for(let j=0; j<18; j++) {
      curEmojiPixels[i][j] = Array(3);
    }
  }

  gray_glyph = new Glyph();
  refreshGridData();
  modeChangedEvent();
}

function sliderUpdated() {
    redraw();
}

function mouseClicked() {
  if (mouseX > width/4) {
    refreshGridData();
  }
  redraw();
}

function dataInterpolate(data1, data2, val) {
  let d = new Array(3);
  for(let i=0; i<3; i++) {
    d[i] = lerp(data1[i], data2[i], val);
  }
  return d;
}

let numGridRows;
let numGridCols;
let gridValues; // row, col order
let gridOffsetX, gridOffsetY;
let gridSpacingX, gridSpacingY;
// Generate data for putting glyphs in a grid

function clamp(num, min, max) {
  return Math.min(Math.max(num, min), max);
}

function refreshGridData() {
  let mode = modeSelector.value();
  let glyphSize = parseInt(sizeSelector.value(), 10);

  if (mode == "image") {
    if(glyphSize == 32) {
      numGridCols = 18;
      numGridRows = 17;
      gridOffsetX = 320;
      gridSpacingX = 31;
      gridOffsetY = 2;
      gridSpacingY = 29;
    }
    else if(glyphSize == 64) {
      numGridCols = 10;
      numGridRows = 9;
      gridOffsetX = 280;
      gridSpacingX = 66;
      gridOffsetY = -18;
      gridSpacingY = 59;
    }
    else if(glyphSize == 128) {
      numGridCols = 6;
      numGridRows = 5;
      gridOffsetX = 164;
      gridSpacingX = 132;
      gridOffsetY = -50;
      gridSpacingY = 118;
    }
    else if(glyphSize == 256) {
      numGridCols = 3;
      numGridRows = 3;
      gridOffsetX = 172;
      gridSpacingX = 262;
      gridOffsetY = -100;
      gridSpacingY = 234;
    }
  }
  else if(glyphSize == 128) {
    numGridCols = 6;
    numGridRows = 3;
    gridOffsetX = 38;
    gridSpacingX = 156;
    gridOffsetY = 32;
    gridSpacingY = 166;
  }
  else if(glyphSize == 256) {
    numGridCols = 3;
    numGridRows = 1;
    gridOffsetX = 20;
    gridSpacingX = 320;
    gridOffsetY = 100;
    gridSpacingY = 500;
  }
  else if(glyphSize == 64) {
    numGridCols = 12;
    numGridRows = 6;
    gridOffsetX = 15;
    gridSpacingX = 78;
    gridOffsetY = 15;
    gridSpacingY = 81;
  }
  else if(glyphSize == 32) {
    numGridCols = 21;
    numGridRows = 11;
    gridOffsetX = 22;
    gridSpacingX = 44;
    gridOffsetY = 22;
    gridSpacingY = 42;
  }
  gridValues = new Array(numGridRows);
  for (let i=0; i<numGridRows; i++) {
    gridValues[i] = new Array(numGridCols);
    for (let j=0; j<numGridCols; j++) {
      gridValues[i][j] = new Array(8);
    }
  }
  if (mode == "gradient" || mode == 'oddball') {
    let top_left = Array(3);
    let top_right = Array(3);
    let bottom_left = Array(3);
    let bottom_right = Array(3);
    for (let k=0; k<3; k++) {
      top_left[k] = random(max_vals[k]);
      top_right[k] = random(max_vals[k]);
      bottom_left[k] = random(max_vals[k]);
      bottom_right[k] = random(max_vals[k]);
    }
    for (let i=0; i<numGridRows; i++) {
      let frac_down = 0;
      if(numGridRows != 1) {
        frac_down = i / (numGridRows - 1.0);
      }
      d_left = dataInterpolate(top_left, bottom_left, frac_down);
      d_right = dataInterpolate(top_right, bottom_right, frac_down);
      for (let j=0; j<numGridCols; j++) {
        let frac_over = 0;
        if(numGridCols != 0) {
          frac_over = j / (numGridCols - 1.0);
        }
        gridValues[i][j] = dataInterpolate(d_left, d_right, frac_over);
      }
    }
    if (mode == 'oddball') {
      // replace an entry at random
      oddball_row = Math.floor(random(numGridRows))
      oddball_col = Math.floor(random(numGridCols))
      for (let k=0; k<3; k++) {
        gridValues[oddball_row][oddball_col][k] = random(max_vals[k]);
      }
    }
  }
  else if(mode == "image") {
    for (let i=0; i<numGridRows; i++) {
      for (let j=0; j<numGridCols; j++) {
        for (let k=0; k<3; k++) {
          gridValues[i][j][k] = curEmojiPixels[i][j][k];
        }
      }
    }
  }
  else {
    for (let i=0; i<numGridRows; i++) {
      for (let j=0; j<numGridCols; j++) {
        for (let k=0; k<3; k++) {
          gridValues[i][j][k] = random(max_vals[k]);
        }
      }
    }
  }
}

function sizeChangedEvent() {
  let mode = modeSelector.value();
  if (mode != 'edit') {
    refreshGridData();
  }
  redraw();
}

function guideChangedEvent() {
  show_oddball = guideCheckbox.checked();
  redraw();
}

function modeChangedEvent() {
  let mode = modeSelector.value();

  // enable/disable sliders
  if (mode === 'edit') {
    // disable the button
    // button.attribute('disabled','');

    // enable the size selector
    sizeSelector.removeAttribute('disabled');

    // enable the first four sliders
    for(let i=0; i<3; i++) {
      val_sliders[i].removeAttribute('disabled');  
    }
  }
  else {
    // enable the button
    // button.removeAttribute('disabled');

    // disable the sliders
    for(let i=0; i<3; i++) {
      val_sliders[i].attribute('disabled','');
    }

    // enable the size selector
    // sizeSelector.removeAttribute('disabled');

    // refresh data
    refreshGridData();
  }
  if (mode === "image") {
    // get current emoji image
    let offsetX = 36 * (curEmoji % 38);
    let offsetY = 36 * Math.floor(curEmoji / 38);

    let squareOffsets = [ [0,0], [0,1], [1,1], [1, 0] ];
    curEmojiImg.copy(emojiImg, offsetX, offsetY, 36, 36, 0, 0, 36, 36);
    curEmojiImg.loadPixels();
    for(let i=0; i<17; i++) {
      // i is y
      let maxX = 18;
      let offsetX = 0;
      if (i%2 == 1) {
        maxX = 17;
        offsetX = 1;
      }
      for(let j=0; j<maxX; j++) {
        // j is x
        let sumColor = [0, 0, 0];
        for(let k=0; k<4; k++) {
          // k is summing over 4 adacent pixels
          let curColor = curEmojiImg.get(j*2 + squareOffsets[k][0] + offsetX, 1 + i*2 + squareOffsets[k][1]);
          for(let l=0; l<3; l++) {
            sumColor[l] += curColor[l] / 4.0;
          }
        }
        let curColor = color(sumColor);
        curEmojiColors[i][j] = curColor;
        let rgba = curColor._array;
        let rgb = [ rgba[0], rgba[1], rgba[2] ];
        let hscol = hsluv.rgbToHsluv(rgb);
        curEmojiPixels[i][j][0] = hscol[0];
        curEmojiPixels[i][j][1] = hscol[1];
        curEmojiPixels[i][j][2] = hscol[2];
      }
    }
    // refresh data
    refreshGridData();
  }

  redraw();
}

function buttonPressedEvent() {
  refreshGridData();
  redraw();
}

// function fillHsluv(h, s, l) {
//   var rgb = hsluv.hsluvToRgb([h, s, l]);
//   fill(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
// }

function ColorGlyph() {
  this.draw = function(values, size) {
    let rgb = hsluv.hsluvToRgb(values);
    fillHsluv(values[0], values[1], values[2]);
    // print(values);
    // fill(rgb[0]*255, rgb[1]*255, rgb[2]*255);
    stroke(0);
    let s2 = size/2;
    ellipse(s2, s2, size);
  }
}
let color_glyph = new ColorGlyph();

function highlightGlyph(glyphSize) {
  let halfSize = glyphSize / 2.0;
  stroke(0, 0, 255, 128);
  noFill();
  strokeWeight(4);
  ellipse(halfSize, halfSize, glyphSize+4);
  fill(0);
  strokeWeight(1);
}

function getGyphObject() {
  return gray_glyph;
}

function drawGlyph(glyphValues, glyphSize) {
  let shawdowShift = glyphSize / 5.0;
  let glyphMode = glyphSelector.value();
   if(glyphMode != "glyph") {
    translate(-shawdowShift, -shawdowShift);
    color_glyph.draw(glyphValues, glyphSize);
    translate(shawdowShift, shawdowShift);
  }
  if(glyphMode != "color") {
    gray_glyph.draw(glyphValues, glyphSize);
  }
}

function drawDriveMode() {
  let glyphSize = 320;
  let halfSize = glyphSize / 2;

  background(backgroundColor);
  let middle_x = canvasWidth / 2;
  let middle_y = canvasHeight / 2;
  middle_x = middle_x + glyphSize / 10.0;
  middle_y = middle_y + glyphSize / 10.0;
  let val = [0,0,0];
  for(i=0; i<3; i++) {
    val[i] = val_sliders[i].value() / 10.0;
  }

  resetMatrix();
  translate(middle_x - halfSize, middle_y - halfSize);
  drawGlyph(val, glyphSize);

  if (show_oddball) {
    resetMatrix();
    translate(middle_x - halfSize, middle_y - halfSize);
    highlightGlyph(glyphSize)
  }

  // resetMatrix();
  // translate(middle_x + halfSize + 32, middle_y - halfSize);
  // color_glyph.draw(val, glyphSize);
}

function drawGridMode() {
  let mode = modeSelector.value();

  let glyphSize = parseInt(sizeSelector.value(), 10);
  background(backgroundColor);
  if (show_oddball &&  mode == 'oddball') {
    resetMatrix();
    translate(gridOffsetX + oddball_col * gridSpacingX, gridOffsetY + oddball_row * gridSpacingY);
    highlightGlyph(glyphSize)
  }
  let hexOffset = (mode == "image");
  for (let i=0; i<numGridRows; i++) {
    let tweakedNumGridCols = numGridCols;
    let offsetX = 0;
    if (hexOffset && i%2 == 1) {
      offsetX = gridSpacingX / 2;
      tweakedNumGridCols = numGridCols - 1;
    }
    for (let j=0; j<tweakedNumGridCols; j++) {
      resetMatrix();
      translate(gridOffsetX + j * gridSpacingX + offsetX, gridOffsetY + i * gridSpacingY);
      drawGlyph(gridValues[i][j], glyphSize);
      resetMatrix();
    }
  }
}

function colorCopyArray(c) {
  d = Array(18);
  for(let i=0; i<18; i++) {
    d[i] = Array(18);
    for(let j=0; j<18; j++) {
      d[i][j] = c[i][j];
    }
  }
  return d;
}

function checkImageUpdate() {
  let mode = modeSelector.value();

  isSwappingEmoji = false;
  if (mode == "image") {
    now = millis();
    if(lastKeyPressedTime + 1000 * secondsUntilSwapMode < now) {
      // key not pressed recently
      if(lastEmojiSwappedTime + 1000 * secondsPerEmoji < now) {
        prevEmoji = curEmoji;
        prevEmojiColors = colorCopyArray(curEmojiColors);
        // no swaps recently
        updateEmoji(1);
        nextEmojiColors = colorCopyArray(curEmojiColors);
        lastEmojiSwappedTime = now;
      }
      if(now - lastEmojiSwappedTime < 1000) {
        isSwappingEmoji = true;
        emojiSwapLerp = (now - lastEmojiSwappedTime) / 1000.0;
        // print("LERP: " + emojiSwapLerp);
        for (let i=0; i<numGridRows; i++) {
          for (let j=0; j<numGridCols; j++) {
            // let curColor = lerpColor(prevEmojiColors[i][j], nextEmojiColors[i][j], emojiSwapLerp);
            let curColor = prevEmojiColors[i][j];
            if (curColor) {
              curColor = lerpColor(prevEmojiColors[i][j], nextEmojiColors[i][j], emojiSwapLerp);
              curEmojiPixels[i][j][0] = curColor._getHue();
              curEmojiPixels[i][j][1] = curColor._getSaturation();
              curEmojiPixels[i][j][2] = curColor._getBrightness();
            }
          }
        }
        refreshGridData();
      }
      else {
        for (let i=0; i<numGridRows; i++) {
          for (let j=0; j<numGridCols; j++) {
            let curColor = nextEmojiColors[i][j];
            if (curColor) {
              curEmojiPixels[i][j][0] = curColor._getHue();
              curEmojiPixels[i][j][1] = curColor._getSaturation();
              curEmojiPixels[i][j][2] = curColor._getBrightness();
            }
          }
        }
        refreshGridData();
      }
    }
  }
}

let is_drawing = false;
function draw () {
  if (is_drawing) {
    return;
  }
  is_drawing = true;
  let mode = modeSelector.value();

  if (mode == "sketch") {
    image(sketchImg, 0, 0, width, height);
    is_drawing = false;
    return;
  }

  checkImageUpdate();

  if (mode == 'edit') {
    drawDriveMode();
  }
  else {
    drawGridMode();
  }
  resetMatrix();
  if (mode == "image") {
    image(curEmojiImg, 96, height-32-36);
  }
  is_drawing = false;
}

function keyTyped() {
  if (key == '!') {
    saveBlocksImages();
  }
  else if (key == '@') {
    saveBlocksImages(true);
  }
  else if (key == ' ') {
    refreshGridData();
    redraw();
  }
  else if (key == 'd') {
    let curGlyph = glyphSelector.value()
    if(curGlyph == "color") {
      glyphSelector.value('glyph');
    }
    else if(curGlyph == "glyph") {
      glyphSelector.value('both');
    }
    else if(curGlyph == "both") {
      glyphSelector.value('color');
    }
    redraw();
  }
  else if (key == 'c') {
    let old_value = guideCheckbox.checked();
    guideCheckbox.checked(!old_value);
    guideChangedEvent();
  }
  else if (key == '1') {
    sizeSelector.value('32');
    sizeChangedEvent()
  }
  else if (key == '2') {
    sizeSelector.value('64');
    sizeChangedEvent()
  }
  else if (key == '3') {
    sizeSelector.value('128');
    sizeChangedEvent()
  }
  else if (key == 's') {
    modeSelector.value('sketch');
    modeChangedEvent()
  }
  else if (key == 'e') {
    modeSelector.value('edit');
    modeChangedEvent()
  }
  else if (key == 'g') {
    modeSelector.value('gradient');
    modeChangedEvent()
  }
  else if (key == 'r') {
    modeSelector.value('random');
    modeChangedEvent()
  }
  else if (key == 'o') {
    modeSelector.value('oddball');
    modeChangedEvent()
  }
  else if (key == 'i') {
    modeSelector.value('image');
    modeChangedEvent()
  }
}

function updateEmoji(offset) {
    curEmoji = (curEmoji + NUM_EMOJI + offset) % NUM_EMOJI;
    modeChangedEvent()
}

function keyPressed() {
  lastKeyPressedTime = millis();

  if (keyCode == LEFT_ARROW) {
    updateEmoji(-1);
  }
  else if (keyCode == RIGHT_ARROW) {
    updateEmoji(1);
  }
  else if (keyCode == UP_ARROW) {
    updateEmoji(-38);
  }
  else if (keyCode == DOWN_ARROW) {
    updateEmoji(38);
  }
}

function mouseMoved() {
  lastKeyPressedTime = millis();
}

function mouseDragged() {
  lastKeyPressedTime = millis();
}

z_color_helper.js

function fillHsluv(h, s, l) {
  var rgb = hsluv.hsluvToRgb([h, s, l]);
  fill(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
}

function strokeHsluv(h, s, l) {
  var rgb = hsluv.hsluvToRgb([h, s, l]);
  stroke(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
}

function fillUniform(brightness) {
    fillHsluv(0, 0, brightness);
}

function strokeUniform(brightness) {
    strokeHsluv(0, 0, brightness);    
}

z_hsluv-0.0.3.min.js

(function() {function f(a){var c=[],b=Math.pow(a+16,3)/1560896;b=b>g?b:a/k;for(var d=0;3>d;){var e=d++,h=l[e][0],w=l[e][1];e=l[e][2];for(var x=0;2>x;){var y=x++,z=(632260*e-126452*w)*b+126452*y;c.push({b:(284517*h-94839*e)*b/z,a:((838422*e+769860*w+731718*h)*a*b-769860*y*a)/z})}}return c}function m(a){a=f(a);for(var c=Infinity,b=0;b<a.length;){var d=a[b];++b;c=Math.min(c,Math.abs(d.a)/Math.sqrt(Math.pow(d.b,2)+1))}return c}
function n(a,c){c=c/360*Math.PI*2;a=f(a);for(var b=Infinity,d=0;d<a.length;){var e=a[d];++d;e=e.a/(Math.sin(c)-e.b*Math.cos(c));0<=e&&(b=Math.min(b,e))}return b}function p(a,c){for(var b=0,d=0,e=a.length;d<e;){var h=d++;b+=a[h]*c[h]}return b}function q(a){return.0031308>=a?12.92*a:1.055*Math.pow(a,.4166666666666667)-.055}function r(a){return.04045<a?Math.pow((a+.055)/1.055,2.4):a/12.92}function t(a){return[q(p(l[0],a)),q(p(l[1],a)),q(p(l[2],a))]}
function u(a){a=[r(a[0]),r(a[1]),r(a[2])];return[p(v[0],a),p(v[1],a),p(v[2],a)]}function A(a){var c=a[0],b=a[1];a=c+15*b+3*a[2];0!=a?(c=4*c/a,a=9*b/a):a=c=NaN;b=b<=g?b/B*k:116*Math.pow(b/B,.3333333333333333)-16;return 0==b?[0,0,0]:[b,13*b*(c-C),13*b*(a-D)]}function E(a){var c=a[0];if(0==c)return[0,0,0];var b=a[1]/(13*c)+C;a=a[2]/(13*c)+D;c=8>=c?B*c/k:B*Math.pow((c+16)/116,3);b=0-9*c*b/((b-4)*a-b*a);return[b,c,(9*c-15*a*c-a*b)/(3*a)]}
function F(a){var c=a[0],b=a[1],d=a[2];a=Math.sqrt(b*b+d*d);1E-8>a?b=0:(b=180*Math.atan2(d,b)/Math.PI,0>b&&(b=360+b));return[c,a,b]}function G(a){var c=a[1],b=a[2]/360*2*Math.PI;return[a[0],Math.cos(b)*c,Math.sin(b)*c]}function H(a){var c=a[0],b=a[1];a=a[2];if(99.9999999<a)return[100,0,c];if(1E-8>a)return[0,0,c];b=n(a,c)/100*b;return[a,b,c]}function I(a){var c=a[0],b=a[1];a=a[2];if(99.9999999<c)return[a,0,100];if(1E-8>c)return[a,0,0];var d=n(c,a);return[a,b/d*100,c]}
function J(a){var c=a[0],b=a[1];a=a[2];if(99.9999999<a)return[100,0,c];if(1E-8>a)return[0,0,c];b=m(a)/100*b;return[a,b,c]}function K(a){var c=a[0],b=a[1];a=a[2];if(99.9999999<c)return[a,0,100];if(1E-8>c)return[a,0,0];var d=m(c);return[a,b/d*100,c]}function L(a){for(var c="#",b=0;3>b;){var d=b++;d=Math.round(255*a[d]);var e=d%16;c+=M.charAt((d-e)/16|0)+M.charAt(e)}return c}
function N(a){a=a.toLowerCase();for(var c=[],b=0;3>b;){var d=b++;c.push((16*M.indexOf(a.charAt(2*d+1))+M.indexOf(a.charAt(2*d+2)))/255)}return c}function O(a){return t(E(G(a)))}function P(a){return F(A(u(a)))}function Q(a){return O(H(a))}function R(a){return I(P(a))}function S(a){return O(J(a))}function T(a){return K(P(a))}
var l=[[3.240969941904521,-1.537383177570093,-.498610760293],[-.96924363628087,1.87596750150772,.041555057407175],[.055630079696993,-.20397695888897,1.056971514242878]],v=[[.41239079926595,.35758433938387,.18048078840183],[.21263900587151,.71516867876775,.072192315360733],[.019330818715591,.11919477979462,.95053215224966]],B=1,C=.19783000664283,D=.46831999493879,k=903.2962962,g=.0088564516,M="0123456789abcdef";
window.hsluv={hsluvToRgb:Q,rgbToHsluv:R,hpluvToRgb:S,rgbToHpluv:T,hsluvToHex:function(a){return L(Q(a))},hexToHsluv:function(a){return R(N(a))},hpluvToHex:function(a){return L(S(a))},hexToHpluv:function(a){return T(N(a))},lchToHpluv:K,hpluvToLch:J,lchToHsluv:I,hsluvToLch:H,lchToLuv:G,luvToLch:F,xyzToLuv:A,luvToXyz:E,xyzToRgb:t,rgbToXyz:u,lchToRgb:O,rgbToLch:P};})();

z_purview_helper.js

// note: this file is poorly named - it can generally be ignored.

// helper functions below for supporting blocks/purview

function saveBlocksImages(doZoom) {
  if(doZoom == null) {
    doZoom = false;
  }

  // generate 960x500 preview.jpg of entire canvas
  // TODO: should this be recycled?
  var offscreenCanvas = document.createElement('canvas');
  offscreenCanvas.width = 960;
  offscreenCanvas.height = 500;
  var context = offscreenCanvas.getContext('2d');
  // background is flat white
  context.fillStyle="#FFFFFF";
  context.fillRect(0, 0, 960, 500);
  context.drawImage(this.canvas, 0, 0, 960, 500);
  // save to browser
  var downloadMime = 'image/octet-stream';
  var imageData = offscreenCanvas.toDataURL('image/jpeg');
  imageData = imageData.replace('image/jpeg', downloadMime);
  p5.prototype.downloadFile(imageData, 'preview.jpg', 'jpg');

  // generate 230x120 thumbnail.png centered on mouse
  offscreenCanvas.width = 230;
  offscreenCanvas.height = 120;

  // background is flat white  
  context = offscreenCanvas.getContext('2d');
  context.fillStyle="#FFFFFF";
  context.fillRect(0, 0, 230, 120);

  if(doZoom) {
    // pixelDensity does the right thing on retina displays
    var pd = this._pixelDensity;
    var sx = pd * mouseX - pd * 230/2;
    var sy = pd * mouseY - pd * 120/2;
    var sw = pd * 230;
    var sh = pd * 120;
    // bounds checking - just displace if necessary
    if (sx < 0) {
      sx = 0;
    }
    if (sx > this.canvas.width - sw) {
      sx = this.canvas.width - sw;
    }
    if (sy < 0) {
      sy = 0;
    }
    if (sy > this.canvas.height - sh) {
      sy = this.canvas.height - sh;
    }
    // save to browser
    context.drawImage(this.canvas, sx, sy, sw, sh, 0, 0, 230, 120);
  }
  else {
    // now scaledown
    var full_width = this.canvas.width;
    var full_height = this.canvas.height;
    context.drawImage(this.canvas, 0, 0, full_width, full_height, 0, 0, 230, 120);
  }
  imageData = offscreenCanvas.toDataURL('image/png');
  imageData = imageData.replace('image/png', downloadMime);
  // call this function after 1 second
  setTimeout(function(){
    p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png');
  }, 1000);
}