Speed up and slow down time by dragging right and left. Shrink and grow by dragging down and up. r : reset to real time b : reverse time + : zoom in - : zoom out d : toggle drawing style (dots, triangles etc.) t : toggle trails c : toggle colours p: paired vertices (slightly more 3D feeling?)
A fork of Played with Chronosynclastic Repeater by Fergus Murray
xxxxxxxxxx
var startTime;
var oldTime=startTime, leng=108;
var ROUNDIES=132132; // For rounded shapes
var shapeType;//TRIANGLE_STRIP;
var reach=0;
var theTime=startTime;
var enlargement=12;
var direction=-1;
var saturate=360, opacity=180;
var mainFeature=43200;
var backg;
var drawBackground=true;
var doubled=1;
var speed=1;
var starting=true;
var startDistance=0, startEnlargement=1, startX, startY, endX, endY, startTouch;
function setup() {
createCanvas(windowWidth, windowHeight); // Size of the drawing area
startTime=3600*hour()+60*minute()+second()+1; // Calculate how many seconds since the start of the day
// Find day of the year.
var now = new Date();
var start = new Date(now.getFullYear(), 0, 0);
var diff = (now - start) + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000);
var oneDay = 1000 * 60 * 60 * 24;
var day = Math.floor(diff / oneDay)-1; // Number the days from zero.
startTime+=86400*day;
if (daysInMonth (2, year())==29) yearLength=366*86400;
else yearLength=365*86400;
oldTime=startTime;
theTime=startTime;
shapeType=POINTS;//QUADS//TRIANGLE_STRIP;
//noStroke();
//strokeWeight(3);
fill(255);
rectMode(CORNER);
ellipseMode(CENTER);
colorMode(HSB, 360);
textFont('Georgia');
textAlign(CENTER);
textSize(width/12);
oldTime=millis();
background(0, 67, 88); // This doesn't work in this version of Processing
// backg=get();
}
function draw() {
if (focused|starting) {
if (frameCount==10) background(0);
if (drawBackground) {
background(enlargement, 60);
}
noStroke();
//textSize(width/36);
//text(speed, width*6/8, height*1/2);
increment=((millis())-oldTime)*speed/1000.0;
theTime+=increment;
oldTime=millis();
//println(theTime);
//backg.scale(width*0.9,height*0.9); // This is a scheme for having trails disappearing into the background. It seems resource-hungry.
/*var shrink=0.003;
image (backg,width*shrink,height*shrink+1,width*(1.0-2*shrink),height*(1.0-2*shrink));*/
//fill(240,64,51,8);
//rect(0,0,width,height);
translate(height*1/8, height/8);
fill(180, 150, 120);
noStroke();
for (var i=0; i<12; i++) {
ellipse(height*0.1*sin(i*TAU/12), height*0.1*-cos(i*TAU/12), 9+4*(i%3==0), 9+4*(i%3==0));
}
stroke(240);
strokeWeight(4);
line (0, 0, height*0.1*sin(theTime*TAU/60), height*0.1*-cos(theTime*TAU/60)); // Second hand
stroke(280);
strokeWeight(6);
//println(hour());
line (0, 0, height*0.08*sin(theTime*TAU/3600), height*0.08*-cos(theTime*TAU/3600)); // Minute hand
//line (0, 0, height*0.07*sin(TAU*minute()/60), height*0.07*-cos(TAU*minute()/60)); // Minute hand
stroke(320);
strokeWeight(8);
line (0, 0, (0.25+(reach))*height*0.2*sin(theTime*TAU/43200), (0.25+(reach))*height*0.2*-cos(theTime*TAU/43200)); // Hour hand
noStroke();
var offset=-height/4;
//curl(86400,64); // 86400 = 60*60*12 = 12 hours
// rotateX(PI/3); // Only works in P3D mode
translate(width*3/8, height*3/8); // To the centre
//rotateX(PI/8);
drawCurlicue(mainFeature, leng, enlargement, 0, 2); // This is the main one
/*stroke(320); // Extra hour hand, enlarged to correspond to reach of hour foot
strokeWeight(8);
line (0, 0, (0.5+(reach/leng))*height*0.2*sin(theTime*TAU/43200), (0.5+(reach/leng))*height*0.2*-cos(theTime*TAU/43200)); // Hour hand
*///print(reach/leng);
for (var i=0; i<4; i++){ // around-the-clock
push();
rotate(TWO_PI*(i-3)/4);
translate(width/6, 0);
drawCurlicue(60, 9, 12, -i*15, 1); // This repeats once a minute
pop();
}
//var oldSat=saturation;
//saturate=30;
translate(width*1/8,0);
direction=-1;
drawCurlicue(yearLength, 2048, enlargement/4, 0, 1); // Year curlicue
direction=1;
//saturate=oldSat;
translate(width*2/8, -height*3/8); // To the top right
drawCurlicue(60, 12, 12, 0, 1); // 1-minute curlicue (second foot)
translate(-width*6/8, height*6/8); // To the bottom left
drawCurlicue(3600, 60, 7, 0, 1); // 1-hour curlicue (minute foot)
translate(width*6/8, 0); // To the bottom right
drawCurlicue(43200, 108, 6, 0, 1); // 12-hour curlicue (hour foot)
if (keyIsPressed && key=='-') {
enlargement*=(19/20);
}
if (keyIsPressed && (key=='='|key=='+')) {
enlargement*=(20/19);
}
//backg=get();
/*fill(0,0,240);
translate (width/2,height-40);
text(("00"+parseInt(hour())).substr(-2) + " : " + ("00"+parseInt(minute())).substr(-2) + " : " + ("00"+parseInt(second())).substr(-2),0,0); */
} else if (!focused) starting=false;
}
// stretchCurlicue (float[][] curlic) {
function curlicue (fract, leng, stepSize) {
var curli=new Array();
var f=0, x=0, y=0;
var ddf=fract, df=0;
if (direction==-1) {
df=ddf*leng;
// f=df*(leng*(leng-1)/2);
}
for (i=0; i<leng; i+=1) {
f+=df*direction;
df+=ddf*direction;
x+=stepSize*cos(f);
y+=stepSize*sin(f);
curli.push(createVector(x, y));
if (doubled==2) {
curli.push(createVector(x+stepSize*sin(df), y-stepSize*cos(df)));
//curli.push(createVector(x+stepSize*sin(f), y-stepSize*cos(f)));
//curli.push(createVector(x, y));
}
}
endX=x;
endY=y;
/** One way to start at the end is to find it and work backwards
but all we really need is to find the final f and df
// which would be
df=ddf*leng;
f=df*(leng*(leng-1)/2); // Isn't it? Sum of df from 0 to leng - triangle
// */
return curli;
}
function drawCurlicue(period, leng, largeness, phaseShift, mirror) {
var sp=period;
//theTime=startTime+speed*millis()/1000.0;
var sl=leng;
for (var invert=-1; invert<2; invert+=2) {
period=sp;
leng=sl;
var d=0;
var stretch=10;
recursion=5;
stroke(360);
//push(); // Any transformations we do after pushMatrix are undone by popMatrix.
var curlic=curlicue(TWO_PI*(theTime+phaseShift)/period, leng, 1);
//println("x"+curlic[8].x);
noStroke();
fill(200);
//noFill();
stroke(60, opacity*1.5);
verticate=128;
if (shapeType==POINTS) strokeWeight(verticate*0.9);
else if (shapeType==ROUNDIES) strokeWeight(verticate*0.5);
else strokeWeight(verticate*0.04);
push();
scale(largeness/verticate);
//if (startAtEnd) {
for (var mir=0; mir<mirror; mir++){
if (mirror>1) rotate (PI);
if (shapeType!=ROUNDIES)
beginShape(shapeType);
else {
stroke(0, saturate, 360, opacity/2);
line (0, 0, curlic[1].x*verticate, curlic[1].y*verticate);
}
for (var i=0; i<curlic.length; i++) {
if (shapeType==POINTS||shapeType==ROUNDIES) stroke(i*(360/curlic.length), saturate, 360, opacity/2);
else
fill(i*(360/curlic.length), saturate, 360, opacity);
if (shapeType==ROUNDIES && i<curlic.length-1) {
//stroke (360);
line (curlic[i].x*verticate, curlic[i].y*verticate, curlic[i+1].x*verticate, curlic[i+1].y*verticate);
}
else
vertex (curlic[i].x*verticate, curlic[i].y*verticate, i*stretch);
}
if (shapeType!=ROUNDIES)
endShape();
}
pop();
reach=dist(0, 0, curlic[curlic.length-1].x, curlic[curlic.length-1].y)/leng;
/*
noStroke();
for (var i=0; i<leng; i++){
fill(i, 360, 360);
ellipse(curlic[i][0]*enlargement,curlic[i][1]*enlargement, 4, 4);
}
*/
//popMatrix();
}
}
function keyPressed() {
if (key=='t') { // trails
drawBackground=!drawBackground;
if (opacity==180) opacity=40;
else opacity=180;
}
if (key=='r') { // reset to real time
resetTime();
}
if (key=='d') { // Toggle drawing style
if (shapeType==TRIANGLE_STRIP) shapeType=ROUNDIES;
else if (shapeType==TRIANGLES) shapeType=TRIANGLE_STRIP;
else if (shapeType==POINTS) shapeType=TRIANGLES;
else if (shapeType==QUADS) shapeType=POINTS;
else if (shapeType==ROUNDIES) shapeType=QUADS;
}
if (key=='b') { // backwards
speed=-speed;
}
if (key=='c') {
if (saturate==360) saturate=30;
else saturate=360;
}
if (key=='p') {
doubled=3-doubled; // toggle doubling
}
}
function resetTime() {
theTime=startTime+speed*millis()/1000.0;
speed=1;
}
function mouseDragged() {
touchMoved();
/*
if (touches.length==0){
speed*=1+(mouseX-pmouseX)/20;
leng+=(pmouseY-mouseY)*3;
if (leng<1) leng=1;
if (abs(speed)<0.001) speed=0.001;
}*/
}
function mousePressed() {
touchStarted();
}
function mouseReleased() {
if (touches.length==0 && dist(startX, startY, mouseX, mouseY)<20) {
//print("mouseX: " + mouseX);
//print("startX: " + startX);
if (dist(mouseX, mouseY, width*7/8, height-width/8)<width/8) { // Day curlicue
mainFeature=43200;
leng=256;
enlargement=0.018*height;
} else if (dist(mouseX, mouseY, width/8, height-width/8)<width/8) { // Hour curlicue
mainFeature=3600;
leng=96;
enlargement=0.027*height;
} else if (dist(mouseX, mouseY, width*7/8, width*1/8)<width/8) { // Minute curlicue
mainFeature=60;
leng=12;
enlargement=0.096*height;
} else if (dist(mouseX, mouseY, width/8, width*1/8)<width/8) {
resetTime();
} else if (dist(startX, startY, mouseX, mouseY)<20) {
if (millis()-startTouch<100) { // reverse direction
speed=-speed;
}
/*else { // change saturate
if (saturate==360) saturate=30;
else saturate=360;
}*/
}
}
}
function mouseClicked() {
if (dist(mouseX, mouseY, width*7/8, height*7/8)<100) { // Day curlicue
mainFeature=43200;
leng=256;
enlargement=12;
}
if (dist(mouseX, mouseY, width/8, height*7/8)<100) { // Hour curlicue
mainFeature=3600;
leng=96;
enlargement=18;
}
if (dist(mouseX, mouseY, width*7/8, height*1/8)<100) { // Minute curlicue
mainFeature=60;
leng=12;
enlargement=64;
}
if (dist(mouseX, mouseY, width/8, height*1/8)<100) {
resetTime();
}
}
function touchStarted() {
if (touches.length<2) {
startTouch=millis();
startX=mouseX;
startY=mouseY;
}
if (touches.length==2) {
println("but why?");
startDistance=dist(touches[0].x, touches[0].y, touches[1].x, touches[1].y);
startEnlargement=enlargement;
}
if (touches.length==3) {
drawBackground=!drawBackground;
if (opacity==120) opacity=40;
else opacity=120;
}
if (touches.length==4) { // Toggle drawing style
if (shapeType==TRIANGLE_STRIP) shapeType=POINTS;
else shapeType=TRIANGLE_STRIP;
}
}
function touchMoved() {
if (touches.length<2) {
//if (mouseX>height-mouseY){ // If touch is in SE half
if (mouseY>height*3/4) {
speed*=1+(mouseX-pmouseX)/50.0;
} else if (mouseX<width/4) {
leng+=(pmouseY-mouseY)/8;
} else if (mouseY<height/4) {
// Do saturate
saturate=720*mouseX/width-270;
if (saturate<0) saturate=0;
} else if (mouseX>width*3/4) {
// Do trails
fadeout=260*sq((mouseY/height))-20; // Preferred scale: From a bit below zero to maybe 100, for height*3/4>y>height/4
//
if (fadeout<0) {
fadeout=0;
drawBackground=false;
} else drawBackground=true;
if (fadeout>120) fadeout=360;
}
if (leng<3) leng=3;
if (abs(speed)<0.001) speed=0.001*abs(speed)/speed;
} else if (touches.length==2) {
enlargement=startEnlargement*(dist(touches[0].x, touches[0].y, touches[1].x, touches[1].y)/startDistance);
}
}
function touchEnded() {
mouseReleased();
}
function daysInMonth (month, year) { // Use 1 for January, 2 for February, etc.
return new Date(year, month, 0).getDate();
}