xxxxxxxxxx
314
//reference: https://www.sinn.de/en/Modell/U1_B.htm
//press 'r' to toggle reference image
//This example pre-renders assets like the dial and hands.
//Doing so allows more complex drawing to happen once in setup, keeping the loop lightweight
let w = 600,
h = 600,
cx = w / 2, //center x
cy = h / 2,
dialDiameterRatio = 0.9,
dialD = h * dialDiameterRatio,
dialR = dialD / 2,
showReference = false,
showPrettyTime = false, //watches always photographed at 10:10:38
now = new Date();
let dialAsset, //global buffers for pre-rendering dials texture
bezelAsset,
hourHand,
minuteHand,
secondHand,
referenceImage;
function setup() {
createCanvas(w, h);
frameRate(8);
createTexturedDial();
createBezel();
createHands();
imageMode(CENTER);
referenceImage = loadImage("assets/SINN-U1-B.jpg");
}
function draw() {
background(32);
now = new Date();
image(dialAsset, cx, cy);
image(bezelAsset, cx, cy);
let h = now.getHours(),
m = now.getMinutes(),
s = now.getSeconds(),
ms = now.getMilliseconds(),
date = now.getDate();
if (showPrettyTime) {
h = 10;
m = 8;
s = 37;
ms = 500;
date = 8;
}
noStroke();
fill(255);
textAlign(CENTER);
textSize(25);
textFont("Courier");
text(date, 462, cy+8);
push();
translate(cx, cy); //TODO - make global rotationg and centering transform
rotate( (h % 12) * (TWO_PI / 12.0) +
(m / 60.0 * (TWO_PI / 12.0))
);
image(hourHand, 0, 0);
pop();
push();
translate(cx, cy);
rotate( (m % 60) * (TWO_PI / 60.0) +
(s / 60.0 * (TWO_PI / 60.0))
);
image(minuteHand, 0, 0);
pop();
push();
translate(cx, cy);
rotate( (s % 60) * (TWO_PI / 60.0) +
(ms / 1000.0 * (TWO_PI / 60.0))
);
image(secondHand, 0, 0);
pop();
if (showReference) {
image(referenceImage, cx, cy, width * 2, height * 2);
}
}
function createConcentricDial() {
dialAsset = createGraphics(w, h);
dialAsset.noStroke();
let colorA = 0;
let colorB = 64;
let stripe = false;
for (let r = dialD; r > 0; r -= 3) {
stripe ? dialAsset.fill(colorA) : dialAsset.fill(colorB);
stripe = !stripe;
//fill(random(255));
dialAsset.ellipse(cx, cy, r, r);
}
}
function createTexturedDial() {
dialAsset = createGraphics(w, h);
dialAsset.noStroke();
let colorA = color(31, 61, 80);
let colorB = color(55, 86, 104);
dialAsset.fill(colorA);
dialAsset.ellipse(cx, cy, dialR * 2, dialR * 2);
dialAsset.stroke(colorB);
dialAsset.strokeWeight(1.2);
for (let r = 1; r < dialR - 1; r++) {
for (let angle = 0; angle < TWO_PI; angle += 0.01) {
if (random(100) > 50) {
dialAsset.point(cx + cos(angle) * r, cy + sin(angle) * r);
}
}
}
//minute track and hour markers
let thetaStep = TWO_PI / 60;
dialAsset.stroke(255);
dialAsset.fill(255);
dialAsset.rectMode(CENTER);
for (let i = 0; i < 60; i++) {
dialAsset.push();
dialAsset.translate(cx, cy);
dialAsset.rotate(-HALF_PI); //Move 0 angle to the noon position
dialAsset.rotate(thetaStep * i);
if (i % 5 != 0) { //the 12 hour 't' markers are inset and larger
dialAsset.rect(dialR * 0.87, 0, 10, 5);
} else {
dialAsset.rect(dialR * 0.8675, 0, 10, 7);
if (i==0) { //12 noon marker special double rectangle
dialAsset.rect(dialR * 0.7675, 0, 45, 30);
dialAsset.rect(dialR * 0.625, 0, 18, 30);
} else
if (i%15==0) { //quarter hour or 3-6-9 markers large rectangle
dialAsset.rect(dialR * 0.775, 0, 40, 30);
} else { //remaining hours small rectangle
dialAsset.rect(dialR * 0.815, 0, 18, 30);
}
}
dialAsset.pop();
}
//text
dialAsset.stroke(255);
dialAsset.fill(255);
dialAsset.textAlign(CENTER);
dialAsset.textSize(30);
dialAsset.textStyle(BOLD);
dialAsset.text("U1", cx, cy * 1.36);
dialAsset.textSize(12);
dialAsset.text("A U T O M A T I K", cx, cy * 1.45);
dialAsset.textSize(10);
dialAsset.textStyle(NORMAL);
dialAsset.text("1 0 0 0 m / 1 0 0 b a r", cx, cy * 1.525);
dialAsset.push();
dialAsset.translate(cx-47, cy * 1.725);
dialAsset.rotate(0.2);
dialAsset.text("M a d e b y", 0, 0);
dialAsset.pop();
dialAsset.push();
dialAsset.translate(cx+47, cy * 1.725);
dialAsset.rotate(-0.2);
dialAsset.text("J e f f r e y", 0, 0);
dialAsset.pop();
//Date window
dialAsset.stroke(0);
dialAsset.strokeWeight(2);
dialAsset.fill(16);
dialAsset.rect(cx*1.54, cy, 38, 25);
}
function createBezel() {
//TODO: make stroke Weights proportional to size
bezelAsset = createGraphics(w, h);
bezelAsset.strokeWeight(50);
bezelAsset.stroke(188, 180, 177, 255);
bezelAsset.noFill();
bezelAsset.ellipse(cx, cy, dialD, dialD);
bezelAsset.strokeWeight(10);
bezelAsset.stroke(118, 114, 110);
bezelAsset.ellipse(cx, cy, dialD + 40, dialD + 40);
bezelAsset.stroke(64, 64, 64);
bezelAsset.strokeWeight(4);
bezelAsset.ellipse(cx, cy, dialD - 50, dialD - 50);
bezelAsset.noFill();
bezelAsset.stroke(120,120,120);
bezelAsset.strokeWeight(2);
bezelAsset.ellipse(cx, cy, dialD-26, dialD-26);
bezelAsset.push();
bezelAsset.translate(cx, cy);
bezelAsset.rotate(-PI/2);
bezelAsset.rectMode(CENTER);
for (let i=0; i<=60; i++) {
bezelAsset.push();
bezelAsset.rotate(TWO_PI/60 * i);
if (i%5==0) {
bezelAsset.stroke(32);
bezelAsset.fill(32);
bezelAsset.rect(dialD/2-5,0,4,12);
} else {
if (i>15) {
bezelAsset.stroke(255,60,60);
bezelAsset.fill(255,0,0);
bezelAsset.rect(dialD/2-5,0,6,3);
}
}
bezelAsset.pop();
}
bezelAsset.pop();
}
function createHands() {
//TODO: make stroke Weights proportional to size
minuteHand = createGraphics(50, 500);
hourHand = createGraphics(50, 500);
secondHand = createGraphics(50, 500);
let shadow = createGraphics(50, 500); //will hold a temporary drop shadow asset that gets blurred into the hand assets
//Shadow. Figure out the hand w/o the shadow first (below).
//Then create a shadow using the same shapes, heavier black strokes
//Render it first so it can be drawn below the hand
shadow.stroke(0, 0, 0);
shadow.blendMode(MULTIPLY);
shadow.strokeWeight(4);
shadow.noFill();
shadow.rect(10,41,30,180);
shadow.rect(21,41,8,-23);
shadow.rect(10,215,30,30);
shadow.ellipse(25,250,30,30);
//minute hand
minuteHand.image(shadow, 0, 0); //add the shadow.
minuteHand.filter(BLUR, 4); //blur it - rest of hand will be drawn over it
minuteHand.blendMode(BLEND);
minuteHand.strokeWeight(1);
minuteHand.stroke(255);
minuteHand.fill(255);
minuteHand.rect(10,41,30,180); //main white part
minuteHand.rect(21,41,8,-23); //pointer
minuteHand.stroke(25);
minuteHand.fill(25);
minuteHand.rect(9,215,32,30);
minuteHand.ellipse(25,250,33,33);
shadow = createGraphics(50, 500);
//shadow
shadow.stroke(0, 0, 0);
shadow.blendMode(MULTIPLY);
shadow.strokeWeight(4);
shadow.noFill();
shadow.rect(10,130,30,60); //main white part
shadow.rect(21,130,8,-23); //pointer
shadow.rect(9,189,32,56);
shadow.ellipse(25,250,30,30);
//hour hand
hourHand.image(shadow, 0, 0);
hourHand.filter(BLUR, 3); //closest to dial so sharpest shadow
hourHand.blendMode(BLEND);
hourHand.strokeWeight(1);
hourHand.stroke(255);
hourHand.fill(255);
hourHand.rect(10,130,30,60); //main white part
hourHand.rect(21,130,8,-23); //pointer
hourHand.stroke(20);
hourHand.fill(20);
hourHand.rect(9,189,32,56); //base of hand
hourHand.ellipse(25,250,33,33);
//second hand shadow
shadow = createGraphics(50, 500);
shadow.stroke(0, 0, 0);
shadow.blendMode(MULTIPLY);
shadow.strokeWeight(4);
shadow.noFill();
shadow.rectMode(CENTER);
shadow.rect(25,65,8,100);
shadow.rect(25,190,8,170);
shadow.ellipse(25,250,25,25);
shadow.rect(25,65,25,25);
//second hand
secondHand.image(shadow, 0, 0);
secondHand.filter(BLUR, 4); //farthest from dial so more blur
secondHand.blendMode(BLEND);
secondHand.strokeWeight(1);
secondHand.stroke(255);
secondHand.fill(255);
secondHand.rectMode(CENTER);
secondHand.rect(25,65,8,100);
secondHand.stroke(30);
secondHand.fill(30);
secondHand.rect(25,190,8,170);
secondHand.ellipse(25,250,25,25);
secondHand.rect(25,65,25,25);
}
function keyPressed() {
if (key == "r") {
showReference = !showReference;
}
if (key == "p") {
showPrettyTime = !showPrettyTime;
}
}