block by dribnet 8f611cc0956fa74c32655c26504d5081

MDDN342 Assignment 2: Randomised Collections

Full Screen

PS2 MDDN 342 2019

In-class example of:

index.html

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.3/seedrandom.min.js"></script>
    <script src="https://d3js.org/d3-random.v1.min.js"></script>
    <script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
    <script language="javascript" type="text/javascript" src="z_focused_random.js"></script>
    <script language="javascript" type="text/javascript" src="face_code.js"></script>
    <script language="javascript" type="text/javascript" src="arrangement.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>
<a href="index.html">arrangement</a>
(<a href="arrangement.js">arrangement code</a>, 
<a href="face_code.js">face code</a>)<br>
<a href="editor.html">editor</a>
(<a href="editor.js">editor code</a>, 
<a href="face_code.js">face code</a>)<br>
<a href="sketch.html">sketch</a>
        </div>
        <div class="inner" id="controls" height="500px">
            <table>
                <tr>
                    <td></td>
                    <td id="slider1Container"></td>
                </tr>
                <tr>
                    <td></td>
                    <td id="slider2Container"></td>
                </tr>
                <tr>
                    <td></td>
                    <td id="slider3Container"></td>
                </tr>
                <tr>
                    <td></td>
                    <td id="slider4Container"></td>
                </tr>
                <tr>
                    <td></td>
                    <td id="slider5Container"></td>
                </tr>
                <tr>
                    <td></td>
                    <td id="selector1Container"></td>
                </tr>
            </table>
        </div>
    </div>
</table>
</body>

arrangement.js

/*
 * This program draws your arrangement of faces on the canvas.
 */

const canvasWidth = 960;
const canvasHeight = 500;
let curRandomSeed = 0;

let lastSwapTime = 0;
const millisPerSwap = 5000;

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

  curRandomSeed = int(focusedRandom(0, 1000));

  // rotation in degrees
  angleMode(DEGREES);
}

function changeRandomSeed() {
  curRandomSeed = curRandomSeed + 1;
  lastSwapTime = millis();
}

// global variables for colors
const bg_color1 = [225, 206, 187];

function mouseClicked() {
  changeRandomSeed();
}

function draw () {
  if(millis() > lastSwapTime + millisPerSwap) {
    changeRandomSeed();
  }

  // reset the random number generator each time draw is called
  resetFocusedRandom(curRandomSeed);

  // clear screen
  background(50);
  noStroke();

  let faceWidth;
  let earSize, earDist;
  let faceColor;

  let gridWidth = 10;
  let gridHeight = 6;

  // draw a 5x3 grid of faces
  let w = canvasWidth / gridWidth;
  let h = canvasHeight / gridHeight;
  for(let i=0; i<gridHeight; i++) {
    for(let j=0; j<gridWidth; j++) {
      let y = h/2 + h*i;
      let x = w/2 + w*j;
      // center face
      push();
      translate(x, y);
      scale(w/25, h/25);
      let faceColorSpinner = int(focusedRandom(1, 9));
      if(faceColorSpinner >= 2 && faceColorSpinner <= 3) {
        faceColor = 1;
      }
      else if(faceColorSpinner >= 4 && faceColorSpinner <= 6) {
        faceColor = 2;
      }
      else if(faceColorSpinner == 7) {
        faceColor = 3;
      }
      else {
        faceColor = 4;
      }
      if(faceColor == 1) {
        earSize = focusedRandom(5, 20, 1);
      }
      else {
        earSize = focusedRandom(0, 8, 2);
      }
      earDist = focusedRandom(0, 10, 4);        
      drawMickeyMouse(earSize, earDist, faceColor);
      pop();
    }
  }
}

function keyTyped() {
  if (key == '!') {
    saveBlocksImages();
  }
  else if (key == '@') {
    saveBlocksImages(true);
  }
}

editor.html

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.3/seedrandom.min.js"></script>
    <script src="https://d3js.org/d3-random.v1.min.js"></script>
    <script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
    <script language="javascript" type="text/javascript" src="face_code.js"></script>
    <script language="javascript" type="text/javascript" src="editor.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>
<a href="index.html">arrangement</a>
(<a href="arrangement.js">arrangement code</a>, 
<a href="face_code.js">face code</a>)<br>
<a href="editor.html">editor</a>
(<a href="editor.js">editor code</a>, 
<a href="face_code.js">face code</a>)<br>
<a href="sketch.html">sketch</a>
        </div>
        <div class="inner" id="controls" height="500px">
            <table>
                <tr>
                    <td>Ear Size</td>
                    <td id="slider1Container"></td>
                </tr>
                <tr>
                    <td>Ear Spacing</td>
                    <td id="slider2Container"></td>
                </tr>
                <tr>
                    <td>Colour</td>
                    <td id="slider3Container"></td>
                </tr>
                <tr>
                    <td>-----</td>
                    <td id="slider4Container"></td>
                </tr>
                <tr>
                    <td>------</td>
                    <td id="slider5Container"></td>
                </tr>
                <tr>
                    <td>Setting 6</td>
                    <td id="slider6Container"></td>
                </tr>
                <tr>
                    <td>Setting 7</td>
                    <td id="slider7Container"></td>
                </tr>
                <tr>
                    <td>Setting 8</td>
                    <td id="slider8Container"></td>
                </tr>
                <tr>
                    <td>Setting 9</td>
                    <td id="slider9Container"></td>
                </tr>
                <tr>
                    <td>Setting 10</td>
                    <td id="slider10Container"></td>
                </tr>
                <tr>
                    <td>Show Target</td>
                    <td id="checkbox1Container"></td>
                </tr>
                <tr>
                    <td>Face</td>
                    <td id="selector1Container"></td>
                </tr>
            </table>
        </div>
    </div>
</table>
</body>

editor.js

/*
 * This editor shows the possible faces that can be created
 */

const canvasWidth = 960;
const canvasHeight = 500;
let slider1, slider2, slider3, slider4, slider5;
let slider6, slider7, slider8, slider9, slider10;
let faceSelector;
let faceGuideCheckbox;

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

  // create sliders
  slider1 = createSlider(0, 100, 50);
  slider2 = createSlider(0, 100, 50);
  slider3 = createSlider(0, 100, 50);
  slider4 = createSlider(0, 100, 50);
  slider5 = createSlider(0, 100, 50);
  slider6 = createSlider(0, 100, 50);
  slider7 = createSlider(0, 100, 50);
  slider8 = createSlider(0, 100, 50);
  slider9 = createSlider(0, 100, 50);
  slider10 = createSlider(0, 100, 50);

  slider1.parent('slider1Container');
  slider2.parent('slider2Container');
  slider3.parent('slider3Container');
  slider4.parent('slider4Container');
  slider5.parent('slider5Container');
  slider6.parent('slider6Container');
  slider7.parent('slider7Container');
  slider8.parent('slider8Container');
  slider9.parent('slider9Container');
  slider10.parent('slider10Container');

  faceGuideCheckbox = createCheckbox('', false);
  faceGuideCheckbox.parent('checkbox1Container');

  faceSelector = createSelect();
  faceSelector.option('1');
  faceSelector.option('2');
  faceSelector.option('3');
  faceSelector.value('1');
  faceSelector.parent('selector1Container');
}

const bg_color = [225, 206, 187];

function draw () {
  strokeWeight(0.2);

  let mode = faceSelector.value();

  background(bg_color);

  let s1 = slider1.value();
  let s2 = slider2.value();
  let s3 = slider3.value();
  let s4 = slider4.value();
  let s5 = slider5.value();
  let s6 = slider6.value();
  let s7 = slider7.value();
  let s8 = slider8.value();
  let s9 = slider9.value();
  let s10 = slider10.value();

  let show_face_guide = faceGuideCheckbox.checked();

  // use same size / y_pos for all faces
  let face_size = canvasWidth / 5;
  let face_scale = face_size / 10;
  let face_y = height / 2;
  let face_x = width / 2;

  push();
  translate(face_x, face_y);
  scale(face_scale);

  push();
  if (mode == '1') {
    // draw 1st face
    let earSize = map(s1, 0, 100, 0, 10);
    let earDist = map(s2, 0, 100, 0, 10);
    // let faceColor = int(map(s3, 0, 100, 1, 4));
    let faceColor = int(map(s3, 0, 100, 1, 5));
    drawMickeyMouse(earSize, earDist, faceColor);
  }

  pop();

  if(show_face_guide) {
    strokeWeight(0.1);
    rectMode(CORNER); 
    noFill()
    stroke(0, 0, 255);
    // ellipse(0, 0, 20, 20);
    rect(-10, -10, 20, 20);
    line(  0, -11,  0, -10);
    line(  0,  10,  0, 11);
    line(-11,   0,-10,  0);
    line( 11,   0, 10,  0);
  }

  pop();
}

function keyTyped() {
  if (key == '!') {
    saveBlocksImages();
  }
  else if (key == '@') {
    saveBlocksImages(true);
  }
}

face_code.js

/*
 * This file should contain code that draws your faces.
 *
 * Each function takes parameters and draws a face that is within
 * the bounding box (-10, -10) to (10, 10).
 *
 * These functions are used by your final arrangement of faces as well as the face editor.
 */


/*
 * earSize can vary from 0 to 10
 * earDist is the distance between ears and varies from 0 to 10
 * faceColor is 1,2,3,4 for yellow,blue,red, or violet respectively
 */
function drawMickeyMouse(earSize, earDist, faceColor) {
  const yellow = color(255, 255, 0);
  const blue = color(0, 0, 200);
  const red = color(200, 0, 0);
  const violet = color(150, 0, 150);
  const error_green = color(0, 255, 0);

  noStroke();

  if(faceColor == 1) {
    fill(yellow);
  }
  else if (faceColor==2) {
    fill(blue);
  }
  else if (faceColor==3) {
    fill(red);
  }
  else if (faceColor == 4) {
    fill(violet);
  }
  else {
    fill(error_green);
  }

  // head
  ellipse(0, 2, 10);

  let earRadius = map(earSize, 0, 10, 4, 7);
  let earXPos = map(earDist, 0, 10, 3, 7);
  ellipse(-earXPos, -5, earRadius);
  ellipse( earXPos, -5, earRadius);
}

focused_random.js

var canvasWidth = 960;
var canvasHeight = 500;
var sliders = [];
var faceSelector;
var curRandomSeed;

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

  curRandomSeed = int(focusedRandom(0, 100));

  // create sliders
  for(i=1; i<=4; i++) {
    var slider = createSlider(0, 100, 50);
    var parentStr = 'slider' + i + 'Container';
    slider.parent(parentStr);
    sliders.push(slider);
  }
  sliders[0].value(0);
  sliders[1].value(100);
  sliders[2].value(0);
  sliders[3].value(50);

  randButton = createButton('randomize');
  randButton.mousePressed(changeRandomSeed);
  randButton.parent('selector1Container');

  // rotation in degrees
  angleMode(DEGREES);
}

function changeRandomSeed() {
  curRandomSeed = curRandomSeed + 1;
}

// global variables for colors
var bg_color = [200, 200, 200];
var fg_color = [255, 255, 255];
var stroke_color = [0, 0, 0];

var num_samples = 2000;
var num_bins = 20;

function draw () {
  resetFocusedRandom(curRandomSeed);

  var min = sliders[0].value();
  var max = sliders[1].value();
  var focus = Math.floor(map(sliders[2].value(), 0, 100, 0, 10))
  var mean = sliders[3].value();
  if(mean < min) {
    mean = min;
    sliders[3].value(mean);
  }
  if(mean > max) {
    mean = max;
    sliders[3].value(mean);
  }

  var samples = []
  var bins = Array(num_bins)
  for(var i=0; i<num_bins; i++) {
    bins[i] = 0;
  }
  var s, b;
  for(var i=0; i<num_samples; i++) {
    s = focusedRandom(min, max, focus, mean);
    b = Math.floor(s*4 / num_bins);
    bins[b] = bins[b] + 1;
  }

  background(bg_color);
  fill(fg_color);
  for(var i=0; i<num_bins; i++) {
    x = i * width / num_bins;
    y = bins[i];
    rect(x, height-y, width/num_bins, y);
  }

  fill(0);
  var info = "min " + min + "  max " + max + "  focus " + focus + "  mean " + mean;
  textSize(36);
  text(info, 300, 100);


}

function keyTyped() {
  if (key == '!') {
    saveBlocksImages();
  }
  else if (key == '@') {
    saveBlocksImages(true);
  }
}

purview.json

{
  "commits": [
    {
      "sha": "f7f76e38bd1c02c783d2a0e1ed815b555abf2560",
      "name": "refined_distribution"
    },
    {
      "sha": "abd752c765c87016a261b58ec508aa2c4677dae9",
      "name": "FocusedRandom API"
    },
    {
      "sha": "062bd19b1898d7f0018e6482257d90f3aeaec2e1",
      "name": "weighted_selection"
    },
    {
      "sha": "802c94f04fe74a5f701555a695be15e2570457ef",
      "name": "two_face_types"
    },
    {
      "sha": "6c45fb54eb95913f76ab652c20b79f88d3d3f590",
      "name": "simple_collection"
    }
  ]
}

sketch.html

<head>
    <style> body {padding: 0; margin: 0;} </style>
</head>
<body style="background-color:white">
<img src="sketch.jpg" width="960" height="480"/>
<p>
<a href="index.html">arrangement</a>
(<a href="arrangement.js">arrangement code</a>, 
<a href="face_code.js">face code</a>)<br>
<a href="editor.html">editor</a>
(<a href="editor.js">editor code</a>, 
<a href="face_code.js">face code</a>)<br>
<a href="sketch.html">sketch</a>
</body>

z_focused_random.js

function resetFocusedRandom() {
  return Math.seedrandom(arguments);
}

function focusedRandom(min, max, focus, mean) {
  // console.log("hello")
  if(max === undefined) {
    max = min;
    min = 0;
  }
  if(focus === undefined) {
    focus = 1.0;
  }
  if(mean === undefined) {
    mean = (min + max) / 2.0;
  }
  if(focus == 0) {
    return d3.randomUniform(min, max)();
  }
  else if(focus < 0) {
    focus = -1 / focus;
  }
  let sigma = (max - min) / (2 * focus);
  let val = d3.randomNormal(mean, sigma)();
  if (val >= min && val < max) {
    return val;
  }
  return d3.randomUniform(min, max)();
}

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);
}