block by dribnet 1e09fe3f3e3294fa49f0ef699628d056

2020 MDDN242 Assignment 1: Software Clock

Full Screen

Clock Drawing Test

Drawing a clock is often a diagnotic in evaluating dementia. Here are some examples from tests. My idea is to use some of these inconsistent clocks as starting points, but to then add additional logic so that the clocks can actually tell time.

index.html

<head>
    <style> body {padding: 0; margin: 0;} </style>
</head>
<body style="background-color:white">
<img src="sketch.jpg" width="960" height="500"/>
<br>
<a href="part1.html">part1</a> 
<a href="part2.html">part2</a> 
<a href="clock.html">clock</a> 
<a href="debug.html">debug</a> 
</body>

clock.html

clock.js

clock_balls.js

/*
 * use p5.js to draw a clock on a 960x500 canvas
 */ 
function draw_clock(obj) {
    // draw your own clock here based on the values of obj:
    //    obj.hours goes from 0-23
    //    obj.minutes goes from 0-59
    //    obj.seconds goes from 0-59
    //    obj.millis goes from 0-999
    //    obj.seconds_until_alarm is:
    //        < 0 if no alarm is set
    //        = 0 if the alarm is currently going off
    //        > 0 --> the number of seconds until alarm should go off

    background(0);
    const ballWidth = 100;

    fill(255, 255, 0);
    let secs = obj.seconds;
    let millis = obj.millis;
    let exactSeconds = secs + millis / 1000.0;

    posX = map(exactSeconds, 0, 60, ballWidth/2, width-ballWidth/2);
    posY = map(60, 0, 100, 0, height);
    ellipse(posX, posY, ballWidth);

    fill(255);
    posX = map(obj.minutes, 0, 59, ballWidth/2, width-ballWidth/2);
    posY = map(40, 0, 100, 0, height);
    ellipse(posX, posY, ballWidth);

    posX = map(obj.hours, 0, 23, ballWidth/2, width-ballWidth/2);
    posY = map(20, 0, 100, 0, height);
    ellipse(posX, posY, ballWidth);
}

clock_bars.js

/*
 * us p5.js to draw a clock on a 960x500 canvas
 */ 
function draw_clock(obj) {
    // draw your own clock here based on the values of obj:
    //    obj.hours goes from 0-23
    //    obj.minutes goes from 0-59
    //    obj.seconds goes from 0-59
    //    obj.millis goes from 0-999
    //    obj.seconds_until_alarm is:
    //        < 0 if no alarm is set
    //        = 0 if the alarm is currently going off
    //        > 0 --> the number of seconds until alarm should go off
    let hours = obj.hours;
    let minutes = obj.minutes;
    let seconds = obj.seconds;
    let millis = obj.millis;
    let alarm = obj.seconds_until_alarm;

    background(255,255,200); //  beige
    fill(128,100,100); // dark grey
    text("Hour: "   + hours, 10, 22);
    text("Minute: " + minutes, 10, 42);
    text("Second: " + seconds, 10, 62);
    text("Millis: " + millis, 10, 82);

    let hourBarWidth   = map(hours, 0, 23, 0, width);
    let minuteBarWidth = map(minutes, 0, 59, 0, width);
    let secondBarWidth = map(seconds, 0, 59, 0, width);
    let millisBarWidth = map(millis, 0, 1000, 0, width);

    noStroke();
    fill(40);
    rect(0, 100, hourBarWidth, 50);
    fill(80);
    rect(0, 150, minuteBarWidth, 50);
    fill(120)
    rect(0, 200, secondBarWidth, 50);
    fill(160)
    rect(0, 250, millisBarWidth, 50);

    // Make a bar which *smoothly* interpolates across 1 minute.
    // We calculate a version that goes from 0...60, 
    // but with a fractional remainder:
    let secondBarWidthChunky  = map(seconds, 0, 59, 0, width);
    let secondsWithFraction   = seconds + (millis / 1000.0);
    let secondBarWidthSmooth  = map(secondsWithFraction, 0, 60, 0, width);

    fill(100, 100, 200)
    rect(0, 350, secondBarWidthChunky, 50);
    fill(120, 120, 240)
    rect(0, 400, secondBarWidthSmooth, 50);
    text("Minute: " + secondsWithFraction, 200, 42);

    fill(200, 100, 100)
    let alarm_message = ""
    if(alarm < 0) {
        alarm_message = "Alarm: Not Set"        
    }
    else if(alarm == 0) {
        alarm_message = "Alarm: GOING OFF"
    }
    else {
        let seconds_remaining = int(alarm);
        alarm_message = "Alarm: will go off in " + seconds_remaining + " seconds"
    }
    text(alarm_message, 400, 42);        
}

clock_tom.js

/*
 * us p5.js to draw a clock on a 960x500 canvas
 */ 

/* size of square */
const s = 24

let numbers = [
  // 0
  [
    [2, 1],
    [3, 1],
    [1, 2],
    [4, 2],
    [1, 3],
    [4, 3],
    [1, 4],
    [4, 4],
    [2, 5],
    [3, 5],
  ],
  // 1
  [
    [2, 2],
    [3, 1],
    [3, 2],
    [3, 3],
    [3, 4],
    [3, 5]
  ],
  // 2
  [
    [1, 1],
    [2, 1],
    [3, 1],
    [4, 2],
    [4, 3],
    [3, 3],
    [2, 4],
    [1, 5],
    [2, 5],
    [3, 5],
    [4, 5]
  ],
  [ // 3
    [1, 1],
    [2, 1],
    [3, 1],
    [4, 2],
    [3, 3],
    [2, 3],
    [4, 4],
    [3, 5],
    [2, 5],
    [1, 5]
  ],
  [ // 4
    [1, 1],
    [3, 1],
    [1, 2],
    [3, 2],
    [1, 3],
    [2, 3],
    [3, 3],
    [4, 3],
    [3, 4],
    [3, 5]
  ],
  [ // 5
    [1, 1],
    [2, 1],
    [3, 1],
    [4, 1],
    [1, 2],
    [1, 3],
    [2, 3],
    [3, 3],
    [4, 4],
    [3, 5],
    [2, 5],
    [1, 5]
  ],
  [ // 6
    [2, 1],
    [3, 1],
    [4, 1],
    [1, 2],
    [1, 3],
    [2, 3],
    [3, 3],
    [1, 4],
    [4, 4],
    [2, 5],
    [3, 5],
  ], //7
  [
    [1, 1],
    [2, 1],
    [3, 1],
    [4, 1],
    [4, 2],
    [3, 3],
    [3, 4],
    [3, 5],
  ],
  [ // 8
    [2, 1],
    [3, 1],
    [1, 2],
    [4, 2],
    [2, 3],
    [3, 3],
    [1, 4],
    [4, 4],
    [2, 5],
    [3, 5],
  ],
  [ // 9
    [2, 1],
    [3, 1],
    [4, 1],
    [1, 2],
    [4, 2],
    [2, 3],
    [3, 3],
    [4, 3],
    [4, 4],
    [4, 5]
  ],
]

function draw_number(num, x, y) {
  /* this resets any previous translations */
  resetMatrix();
  translate(x, y);
  var pixels = numbers[num%numbers.length];
  for(var i=0; i<13; i++) {
    var cur_pixel = pixels[i%pixels.length];
    rect(cur_pixel[0] * s, cur_pixel[1] * s, s, s);
  }
}

function draw_number_interp(frac, num1, num2, x, y) {
  /* this resets any previous translations */
  resetMatrix();
  translate(x, y);
  var pixels1 = numbers[num1%numbers.length];
  var pixels2 = numbers[num2%numbers.length];
  for(var i=0; i<13; i++) {
    var cur_pixel1 = pixels1[i%pixels1.length];
    var cur_pixel2 = pixels2[i%pixels2.length];
    var pos_x = map(frac, 0.0, 1.0, cur_pixel1[0], cur_pixel2[0]);
    var pos_y = map(frac, 0.0, 1.0, cur_pixel1[1], cur_pixel2[1]);
    rect(pos_x * s, pos_y * s, s, s);
  }
}

function digits_from_num(num) {
  let digits = []
  if (num < 10) {
    digits.push(0);
  }
  else {
    n1 = Math.floor(num / 10);
    digits.push(n1);
  }
  n2 = Math.floor(num % 10);
  digits.push(n2);
  return digits;
}

function draw_clock(obj) {
  let hour = obj.hours;
  let minute = obj.minutes;
  let second = obj.seconds;
  let millis = obj.millis;
  let alarm = obj.seconds_until_alarm;

  var hour_pos = [40, height/2 - 3.5 * s];

  // DEBUG CODE TO TEST HOUR ROLLOVER
  // minute = minute + 35; // change based on current time
  // if (minute == 60) {
  //   minute = 0;
  //   hour = 0;
  // }

  // is alarm going off?
  if (alarm == 0) {
    if (second % 2 == 0) {
      background(0,0,100);      
    }
    else {
      background(100,100,0);      
    }
  }
  else {
    background(50);
  }

  noStroke();
  // is alarm going off in next 15 seconds
  if (alarm > 0) {
    fill(100);
    rect(width-50, height-50, 40, 40);
    if (alarm < 15.0) {
      var box_w = map(alarm, 0, 15, width, 0);
      var box_h = map(alarm, 0, 15, height, 0);
      rect(width/2-box_w/2, height/2-box_h/2, box_w, box_h);
    }
  }
  fill(255);

  // HOURS
  next_hour = (hour + 1) % 24;
  digits1 = digits_from_num(hour);
  digits2 = digits_from_num(next_hour);
  if(second >= 50 && minute == 59 && 
      (hour == 9 || hour == 19 || hour == 23)) {
    // minute_fraction_tens = millis  / 1000.0;
    seconds_left = (second - 50) + millis / 1000.0;
    hour_fraction_tens = seconds_left  / 10.0;
  }
  else {
    hour_fraction_tens = 0;
  }
  draw_number_interp(hour_fraction_tens, digits1[0], digits2[0], hour_pos[0] + 0.0 * 5 * s, hour_pos[1]);
  // draw_number(digits1[0], hour_pos[0], hour_pos[1]);

  if(second >= 55 && minute == 59) {
    // minute_fraction_tens = millis  / 1000.0;
    seconds_left = (second - 55) + millis / 1000.0;
    hour_fraction_ones = seconds_left  / 5.0;
  }
  else {
    hour_fraction_ones = 0;
  }
  draw_number_interp(hour_fraction_ones, digits1[1], digits2[1], hour_pos[0] + 1.0 * 5 * s, hour_pos[1]);
  // draw_number(digits1[1], hour_pos[0] + 1.0 * 5 * s, hour_pos[1]);

  // MINUTES
  next_minute = (minute + 1) % 60;
  digits1 = digits_from_num(minute);
  digits2 = digits_from_num(next_minute);
  if(second >= 58 && digits1[1] === 9) {
    // minute_fraction_tens = millis  / 1000.0;
    seconds_left = (second - 58) + millis / 1000.0;
    minute_fraction_tens = seconds_left  / 2.0;
  }
  else {
    minute_fraction_tens = 0;
  }
  draw_number_interp(minute_fraction_tens, digits1[0], digits2[0], hour_pos[0] + 2.5 * 5 * s, hour_pos[1]);

  if(second === 59) {
    minute_fraction_ones = millis  / 1000.0;
  }
  else {
    minute_fraction_ones = 0;
  }
  draw_number_interp(minute_fraction_ones, digits1[1], digits2[1], hour_pos[0] + 3.5 * 5 * s, hour_pos[1]);
  // draw_number(digits1[1], hour_pos[0] + 3.5 * 5 * s, hour_pos[1]);


  // SECONDS
  next_second = (second + 1) % 60;
  second_fraction = millis / 1000.0;
  digits1 = digits_from_num(second);
  digits2 = digits_from_num(next_second);
  // print(digits1);


  if(digits1[1] === 9 && millis > 500) {
    second_fraction_tens = (millis - 500) / 500.0;
  }
  else {
    second_fraction_tens = 0;
  }
  // draw the 10 second position
  draw_number_interp(second_fraction_tens, digits1[0], digits2[0], hour_pos[0] + 5.0 * 5 * s, hour_pos[1]);

  if(millis > 900) {
    second_fraction_ones = (millis-900) / 100.0;
  }
  else {
    second_fraction_ones = 0;
  }
  // draw the 1 second position
  draw_number_interp(second_fraction_ones, digits1[1], digits2[1], hour_pos[0] + 6.0 * 5 * s, hour_pos[1]);
}

debug.html

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/addons/p5.dom.js"></script>
    <script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
    <script language="javascript" type="text/javascript" src="debug.js"></script>
    <script language="javascript" type="text/javascript" src="clock.js"></script>
    <script language="javascript" type="text/javascript" src="runner.js"></script>
</head>
<body style="background-color:white">
    <div class="outer">
        <div class="inner">
            <div id="canvasContainer"></div>
        </div>
    </div>
</table>
<body style="background-color:white">
    <div class="outer">
        <div class="inner">
            <div id="canvasContainer"></div>
        </div>
        <div class="inner" id="controls">
            <table>
                <tr>
                    <td>debug</td>
                    <td id="checkboxDebug"></td>
                </tr>
                <tr>
                    <td>hours</td>
                    <td id="sliderHours"></td>
                    <td>minutes</td>
                    <td id="sliderMinutes"></td>
                    <td>seconds</td>
                    <td id="sliderSeconds"></td>
                    <td>millis</td>
                    <td id="sliderMillis"></td>
                </tr>
                <tr>
                    <td>alarm</td>
                    <td id="checkboxAlarm"></td>
                    <td>alarm_secs</td>
                    <td id="sliderAlarm"></td>
                </tr>
            </table>
        </div>
    </div>
</table>
</body>
<br>
<a href="part1.html">part1</a> 
<a href="part2.html">part2</a> 
<a href="clock.html">clock</a> 
<a href="debug.html">debug</a> 
</body>

debug.js

var DEBUG=true;

var debugCheckbox;
var hourSlider;
var minSlider;
var secSlider;
var millisSlider;
var alarmSlider;

function debug_setup() {
  debugCheckbox = createCheckbox('', false);
  debugCheckbox.parent("checkboxDebug")
  hourSlider = createSlider(0, 23, 12);
  hourSlider.parent("sliderHours")
  minSlider = createSlider(0, 59, 0);
  minSlider.parent("sliderMinutes")
  secSlider = createSlider(0, 59, 0);
  secSlider.parent("sliderSeconds")
  millisSlider = createSlider(0, 999, 0);
  millisSlider.parent("sliderMillis")
  alarmCheckbox = createCheckbox('', false);
  alarmCheckbox.parent("checkboxAlarm")
  alarmSlider = createSlider(0, 60, 0);
  alarmSlider.parent("sliderAlarm")
}

maeda_clock.js

// Update this function to draw you own maeda clock on a 960x500 canvas
function draw_clock(obj) {
  // YOUR MAIN CLOCK CODE GOES HERE
  background(50); //  beige
  fill(200); // dark grey
  textSize(40);
  textAlign(CENTER, CENTER);
  text("YOUR MAEDA CLOCK CODE GOES HERE", width/2, height/2);
}

part1.html

part2.html

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/addons/p5.dom.js"></script>
    <script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
    <script language="javascript" type="text/javascript" src="maeda_clock.js"></script>
    <script language="javascript" type="text/javascript" src="runner.js"></script>
</head>
<body style="background-color:white">
    <div class="outer">
        <div class="inner">
            <div id="canvasContainer"></div>
        </div>
    </div>
</table>
<br>
<a href="maeda_clock.js">(source code)</a> 
<a href="part1.html">part1</a> 
<a href="part2.html">part2</a> 
<a href="clock.html">clock</a> 
<a href="debug.html">debug</a> 
</body>

runner.js

z_purview_helper.js