Skip to content

Instantly share code, notes, and snippets.

@LABCAT
Forked from dribnet/.block
Last active March 21, 2017 03:52
Show Gist options
  • Select an option

  • Save LABCAT/d19f7116a4b6d06638aa160ac326cb93 to your computer and use it in GitHub Desktop.

Select an option

Save LABCAT/d19f7116a4b6d06638aa160ac326cb93 to your computer and use it in GitHub Desktop.
17.1.MDDN242 PS1
license: mit
// 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);
p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png');
}

PS1 MDDN 242 2017 - LABCAT - Shane Watters - 300078996

DIGITAL ANALOG CLOCK

This is a digital clock designed to look like an analog clock. The clock has no hands unlike an analog clock. Instead the passing of seconds is shown by the minute digits rotating 6 degrees every second. The digit/s representing the current hour is/are displayed as a different colour (from other hours) and also rotates in the same manner as the minute digits.

The clockface is also upside down when compared to a traditional analog clock. The reason for this is that you are more likely to start your day at 6AM than 12AM.

Behind the clock, a randomized rainbow pattern is being created. This was added to the design to make it more visually appealing. I found that adding this pattern made it more interesting to keep watching the clock, as the pattern becomes more interesting as time passes.

The final concept and design of the clock grew from the process of developing it. Initially the concept was based on one of Maeda's 12 clocks and my desire to experiement with rotational functionality.
However once I had my initial concept working I felt the design and colour scheme wasn't eye catching enough.

This led me to look at a lot of clock photos which provided the inspiration to redesign the clock and change the colour scheme. The final design still incorporates rotational functionality but looks a lot more visually appealing than my initial concept.

/*
* object to encapsulate the variables and functionality
* required to process the alarm
*/
var alarmProcessor = {
//variables
countdown: 20,
previousSecond : -1,
alarmRadius : 0,
ready: false,
//JSON object to represent each character displayed by the drawMessage function
messageChars: {
1: {
'x': 220,
'y': 250,
'char' : 'A'
},
2: {
'x': 340,
'y': 250,
'char' : 'L'
},
3: {
'x': 460,
'y': 250,
'char' : 'E'
},
4: {
'x': 580,
'y': 250,
'char' : 'R'
},
5: {
'x': 760,
'y': 250,
'char' : 'T'
},
},
//this function will be called when the alarm is set
process: function(second, millis, alarm){
resetMatrix();
//if countdown is greater zero, the alarm is no going off yet
if(this.countdown > 0){
//to create a warning that the alarm is about to go off,
//a circle is drawn from the center of the canvas and gradually grows to fill the canvas
fill(255, 0, 0);
ellipse(480, 250, this.alarmRadius, this.alarmRadius);
//only decrease the countdown variable the current second is not the previous second
if(second != this.previousSecond){
this.previousSecond = second;
this.countdown--;
}
this.alarmRadius++;
}
else if(this.countdown == 0){
clear();
//once the alarm is going off, fill the canvas with a red rectangle
//use a varying level of transparency to create a flashing effect
var transparency = floor(map(millis, 0, 999, 0, 255));
fill(255, 0, 0, transparency);
rect(0, 0, 960, 500);
this.drawMessage();
this.ready = false;
}
},
//draws the message "ALERT" when the alarm is going off
drawMessage: function (){
for(var i =1; i <= 5; i++){
drawCharacter(
this.messageChars[i]['x'],
this.messageChars[i]['y'],
20,
this.messageChars[i]['char'],
0,
Array(255, 255, 255)
);
}
},
//when the alarm is turned off this function is used to reset this object to it's original state
reset: function() {
this.countdown = 20;
this.previousSecond = -1;
this.alarmRadius = 0;
if(!this.ready){
resetMatrix();
fill(255);
rect(0, 0, 960, 500);
this.ready = true;
}
}
}
/*
* json object to represent a collection of characters.
* a character on a traditional digital clock is made of 7 segments
* therefore each element of this object is an array is of 7 values
* each value is the level of transparency for each segment to determine whether or not it can be seen
*/
var charSegments = {
0 : [255,0,255,255,255,255,255],
1 : [0,0,0,0,255,0,255],
2 : [255,255,255,0,255,255,0],
3 : [255,255,255,0,255,0,255],
4 : [0,255,0,255,255,0,255],
5 : [255,255,255,255,0,0,255],
6 : [255,255,255,255,0,255,255],
7 : [255,0,0,0,255,0,255],
8 : [255,255,255,255,255,255,255],
9 : [255,255,255,255,255,0,255],
10 : [255,0,255,255,255,255,255],
11 : [0,0,0,255,255,255,255],
12 : [255,255,255,0,255,255,0],
'A': [255,255,0,255,255,255,255],
'L': [0,0,255,255,0,255,0],
'E': [255,255,255,255,0,255,0],
'R': [255,0,0,255,0,255,0],
'T': [255,0,0,255,0,255,0]
}
/*
* json object to represent each number on the clock face
* each number has a value for the x position, the y position and the rotation amount (in degrees)
*/
var clockFaceNumbers = {
1: {
'x': 385,
'y': 420,
'rotation' : 210
},
2: {
'x': 315,
'y': 345,
'rotation' : 240
},
3: {
'x': 290,
'y': 250,
'rotation' : 270
},
4: {
'x': 310,
'y': 155,
'rotation' : 300
},
5: {
'x': 385,
'y': 85,
'rotation' : 330
},
6: {
'x': 480,
'y': 60,
'rotation' : 360
},
7: {
'x': 565,
'y': 80,
'rotation' : 30
},
8: {
'x': 640,
'y': 145,
'rotation' : 60
},
9: {
'x': 670,
'y': 250,
'rotation' : 90
},
10: {
'x': 635,
'y': 355,
'rotation' : 120
},
11: {
'x': 575,
'y': 420,
'rotation' : 150
},
12: {
'x': 460,
'y': 435,
'rotation' : 180
}
}
/*
* us p5.js to draw a clock on a 960x500 canvas
*/
function draw_clock(hour, minute, second, millis, alarm) {
//set angle mode to degrees
angleMode(DEGREES);
//set the stroke weight to 0
strokeWeight(0);
//variables
var rotationAmount = floor(map(second, 0, 60, 0, 360));
//print(rotationAmount);
var firstMinuteDigit = floor(map(minute, 0, 59, 0, 5.9));
var secondMinuteDigit = minute % 10;
var currentHour = 12;
//if the modulo of hour is not 0 then set currentHour to the modulo
if(hour % 12){
currentHour = hour % 12;
}
//draw rainbow pattern behind the clockface
drawRainbowPattern(millis);
//draw the clock face and highlight the current hour
drawClockFace(currentHour, rotationAmount);
//draw the minute digits
drawCharacter(435, 250, 10, firstMinuteDigit, rotationAmount, Array(70, 151, 255));
drawCharacter(525, 250, 10, secondMinuteDigit, rotationAmount, Array(70, 151, 255));
if(alarm >= 0 && alarm < 21){
//if the alarm has less than 21 seconds until it will go, begin the processing the alarm
alarmProcessor.process(second, millis, alarm);
}
else {
//reset the alarm object when the alarm is turned off
alarmProcessor.reset();
}
}
/**
* draws a random rainbow pattern behind the clock to make the background more visually interesting
*/
function drawRainbowPattern(millis) {
//create a random fill colour
fill(random(255), random(255), random(255));
push();
translate(480, 250);
//map millis to degrees, ignores millis greater than 719 so that the value for degree will be either a whole number +/- 0.5
var degree = map(millis, 0, 719, 0, 359);
//rotate 0.5 of a degree every millisecond
rotate(degree);
rect(0, 0, 480, 2);
pop();
}
/**
* draws the clock background and all the numbers to display on the face
* @param {Number} currentHour - the current hour of the day (from 1-12)
* @param {Number} rotationAmount - the amount of degrees to rotate
*/
function drawClockFace(currentHour, rotationAmount){
var rgb = Array(), rotation = 0;
drawClockBackground();
//draw all the numbers on the clock face
for(var i =1; i <= 12; i++){
if(i == currentHour){
//if "i" is the current hour then change the colour and set it to rotate 6 degrees every second
rgb = Array(236, 189, 9);
rotation = clockFaceNumbers[i]['rotation'] + rotationAmount;
}
else {
rgb = Array(11, 247, 48);
rotation = clockFaceNumbers[i]['rotation'];
}
drawCharacter(
clockFaceNumbers[i]['x'],
clockFaceNumbers[i]['y'],
10,
i,
rotation,
rgb
);
}
}
/**
* draws the clock background
*/
function drawClockBackground() {
fill(0);
ellipse(480, 250, 498, 498);
fill(70, 151, 255);
ellipse(480, 250, 496, 495);
fill(255);
ellipse(480, 250, 492, 492);
fill(2, 4, 103);
ellipse(480, 250, 489, 489);
}
/**
* draws a character on the canvs
* @param {Number} x - the x postion for the center of the character
* @param {Number} y - the y position for the center of the character
* @param {Number} s - the size mulitple to determine how big a character will be
* @param {Number} degrees - the number of degrees to rotate the character around its center
* @param {Array} rgb - an array representing the RGB values that determine the fill colour of the character
*/
function drawCharacter(x, y, s, char, degrees, rgb = Array(255, 255, 255)){
//adjustment variables used to allow the characters to be drawn with x,y point as the center of the shapes
var xAdjuster = -(s * 5) - s / 2;
var yAdjuster = -(s * 9) / 2;
//this resets any previous translations
resetMatrix();
translate(x, y);
rotate(degrees);
//top horizontal segment
fill(rgb[0], rgb[1], rgb[2], charSegments[char][0]);
rect(xAdjuster + s * 4, yAdjuster + 0, s * 3, s);
//middle horizontal segment
fill(rgb[0], rgb[1], rgb[2], charSegments[char][1]);
rect(xAdjuster + s * 4, yAdjuster + s * 4, s * 3, s);
//bottom horizontal segment
fill(rgb[0], rgb[1], rgb[2], charSegments[char][2]);
rect(xAdjuster + s * 4, yAdjuster + s * 8, s * 3, s);
//top-left vertical segment
fill(rgb[0], rgb[1], rgb[2], charSegments[char][3]);
rect(xAdjuster + s * 3, yAdjuster + s, s, s * 3);
//top-right vertical segment
fill(rgb[0], rgb[1], rgb[2], charSegments[char][4]);
rect(xAdjuster + s * 7, yAdjuster + s, s, s * 3);
//bottom-left vertical segment
fill(rgb[0], rgb[1], rgb[2], charSegments[char][5]);
rect(xAdjuster + s * 3, yAdjuster + s * 5, s, s * 3);
//bottom-right vertical segment
fill(rgb[0], rgb[1], rgb[2], charSegments[char][6]);
rect(xAdjuster + s * 7, yAdjuster + s * 5, s, s * 3);
//special additions required for the characters '10' and '12'
if(char == 10 || char == 12){
fill(rgb[0], rgb[1], rgb[2], charSegments[1][4]);
rect(xAdjuster + s, yAdjuster + s, s, s * 3);
fill(rgb[0], rgb[1], rgb[2], charSegments[1][6]);
rect(xAdjuster + s, yAdjuster + s * 5, s, s * 3);
}
//special additions required for the character 'T'
if(char == "T"){
fill(rgb[0], rgb[1], rgb[2], 255);
rect(xAdjuster, yAdjuster + 0, s * 3, s);
}
}
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/addons/p5.dom.js"></script>
<script language="javascript" type="text/javascript" src=".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="sketch.js"></script>
</head>
<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>
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")
}
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/addons/p5.dom.js"></script>
<script language="javascript" type="text/javascript" src=".purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="clock.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
</head>
<body style="background-color:white">
<div class="outer">
<div class="inner">
<div id="canvasContainer"></div>
</div>
</div>
</table>
</body>
{
"commits": [
{
"sha": "8dc8ac4421e2965df492a3803c867ec866fc8bef",
"name": "final"
},
{
"sha": "99e05228cbaa0613220ae099ea758207bc468df1",
"name": "clock_alarm"
},
{
"sha": "2c39db4536395c2a7a2cdbb1d04f18fcaa957730",
"name": "original_clock"
},
{
"sha": "2fb1c1a1346de8b829423fa43f8415bca344b630",
"name": "maeda_clock"
},
{
"sha": "d04f5cd12e3703520416c2fa209d3b96cdf01926",
"name": "sketch"
}
]
}
var canvasWidth = 960;
var canvasHeight = 500;
var prevSec;
var millisRolloverTime;
var nextAlarm;
var debug_is_on = (typeof DEBUG !== 'undefined');
function setup () {
// create the drawing canvas, save the canvas element
var main_canvas = createCanvas(canvasWidth, canvasHeight);
main_canvas.parent('canvasContainer');
// this is true if debug.js is included
if(debug_is_on) {
debug_setup();
}
turn_off_alarm();
}
function turn_on_alarm() {
nextAlarm = millis() + 20000;
print("Alarm on: T minus 20 seconds");
}
function turn_off_alarm() {
nextAlarm = -1;
print("Alarm turned off");
}
function mouseClicked() {
if (debug_is_on && debugCheckbox.checked()) {
return;
}
if (nextAlarm > 0) {
turn_off_alarm();
}
else {
turn_on_alarm();
}
}
// taking ideas from http://cmuems.com/2016/60212/deliverables/deliverables-02/
function draw () {
var H, M, S, mils, alarm;
if (debug_is_on && debugCheckbox.checked()) {
hourSlider.removeAttribute('disabled');
minSlider.removeAttribute('disabled');
secSlider.removeAttribute('disabled');
millisSlider.removeAttribute('disabled');
alarmCheckbox.removeAttribute('disabled');
alarmSlider.removeAttribute('disabled');
H = hourSlider.value();
M = minSlider.value();
S = secSlider.value();
mils = millisSlider.value();
if (alarmCheckbox.checked()) {
alarm = alarmSlider.value();
}
else {
alarm = -1;
}
}
else {
// Fetch the current time
H = hour();
M = minute();
S = second();
if (nextAlarm > 0) {
now = millis();
var millis_offset = nextAlarm - now;
if (millis_offset < -10000 ){
// turn off alarm
nextAlarm = -1;
alarm = -1;
}
else if (millis_offset < 0) {
alarm = 0;
}
else {
alarm = millis_offset / 1000.0;
}
}
else {
alarm = -1;
}
// Reckon the current millisecond,
// particularly if the second has rolled over.
// Note that this is more correct than using millis()%1000;
if (prevSec != S) {
millisRolloverTime = millis();
}
prevSec = S;
mils = floor(millis() - millisRolloverTime);
if (debug_is_on) {
hourSlider.attribute('disabled','');
minSlider.attribute('disabled','');
secSlider.attribute('disabled','');
millisSlider.attribute('disabled','');
alarmCheckbox.attribute('disabled','');
alarmSlider.attribute('disabled','');
hourSlider.value(H);
minSlider.value(M);
secSlider.value(S);
millisSlider.value(mils);
alarmCheckbox.checked(alarm >= 0);
alarmSlider.value(alarm);
}
}
draw_clock(H, M, S, mils, alarm);
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
else if (key == '@') {
saveBlocksImages(true);
}
}
body {
padding: 0;
margin: 0;
background-color:white;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment