-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclock.js
296 lines (229 loc) · 9.44 KB
/
clock.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
var canvas;
var graphics;
var userTimeZoneOffset = new Date().getTimezoneOffset(); // Default offset in minutes
async function fetchTimeZone() {
try {
const response = await fetch('https://ipapi.co/json/');
const data = await response.json();
if (data && data.timezone) {
// Store both timezone name and offset
window.detectedTimezone = data.timezone;
// Create a date in the detected timezone
const tzDate = new Date().toLocaleString('en-US', { timeZone: data.timezone });
const detectedDate = new Date(tzDate);
// Update the timezone offset
userTimeZoneOffset = -detectedDate.getTimezoneOffset();
console.log(`User timezone detected: ${data.timezone}`);
console.log(`Timezone offset: ${userTimeZoneOffset}`);
} else {
console.log('Timezone not detected, using local time zone.');
}
} catch (error) {
console.error('Error fetching timezone:', error);
}
}
// draws a black line segment
function Blackline (x1, y1, x2, y2) {
// Save the current graphics state.
graphics.save()
graphics.beginPath();
graphics.moveTo(x1, y1);
graphics.lineTo(x2,y2);
graphics.strokeStyle = "black";
graphics.stroke();
// Restore the graphics state to its original state.
graphics.restore();
}
// this function is merely a tweak of the one provided above: draws a red line segment
function Redline (x1, y1, x2, y2) {
// Save the current graphics state.
graphics.save();
graphics.beginPath();
graphics.moveTo(x1, y1);
graphics.lineTo(x2,y2);
graphics.strokeStyle = "red";
graphics.stroke();
// Restore the graphics state to its original state.
graphics.restore();
}
function drawCircle(radius, centerX, centerY, numPoints) {
// Save the current graphics state.
graphics.save();
// Begin a new path, clearing any existing path.
graphics.beginPath();
// Calculate the angle increment between each point on the circle.
var angleIncrement = (2 * Math.PI) / numPoints;
// Loop through the number of points specified to create the circle.
for (let i = 0; i <= numPoints; i++) {
// Calculate the current angle (theta) for this point.
var theta = i * angleIncrement;
// Calculate the X and Y coordinates of the current point on the circle.
// The parametric equations for the circle are used here.
var x = centerX + radius * Math.cos(theta);
var y = centerY + radius * Math.sin(theta);
// If it's the first point in the loop, move the pen to that point (without drawing a line).
// Otherwise, draw a line from the previous point to this point.
if (i === 0) {
graphics.moveTo(x, y);
} else {
graphics.lineTo(x, y);
}
}
// Connect the last point to the first point to close the path, creating a closed circle.
graphics.closePath();
// Draw the circle on the canvas using the current stroke style (black line color).
graphics.stroke();
// Restore the graphics state to its original state.
graphics.restore();
}
function grid () {
// Save the current graphics state.
graphics.save();
for (let index = 60; index < 600; index+=60) {
if (index == 300) {
// Drawing vertical and horizontal red lines at center
Redline(index, 0, index, 600);
Redline(0, index, 600, index);
} else {
// Drawing black lines
Blackline(index, 0, index, 600);
Blackline(0, index, 600, index);
}
}
// Restore the graphics state to its original state.
graphics.restore();
}
function drawTics(centerX, centerY, numPoints, radius, lengthFactor) {
// Save the current graphics state.
graphics.save();
// Calculate the angle increment for each tic point.
var angleIncrement = (2 * Math.PI) / numPoints;
// Loop through all the tic points.
for (let i = 0; i < numPoints; i++) {
// Calculate the angle in radians for the current tic.
var theta = i * angleIncrement;
// Check if the current tic is a multiple of 5 (hour tic).
if (i % 5 === 0) {
// Calculate the length of the hour tic.
var hourLength = radius * lengthFactor * 2;
// Calculate coordinates for the inner and outer ends of the hour tic.
var x1 = centerX + ((radius - hourLength) - (radius * lengthFactor)) * Math.cos(theta);
var y1 = centerY + ((radius - hourLength) - (radius * lengthFactor)) * Math.sin(theta);
var x2 = centerX + ((radius - hourLength) + (radius * lengthFactor)) * Math.cos(theta);
var y2 = centerY + ((radius - hourLength) + (radius * lengthFactor)) * Math.sin(theta);
// Draw a longer black line for the hour tic.
Blackline(x1, y1, x2, y2);
}
// Calculate the length of the minute tic.
var minuteLength = radius * lengthFactor / 2;
// Calculate coordinates for the inner and outer ends of the minute tic.
var x3 = centerX + (radius - minuteLength) * Math.cos(theta);
var y3 = centerY + (radius - minuteLength) * Math.sin(theta);
var x4 = centerX + radius * Math.cos(theta);
var y4 = centerY + radius * Math.sin(theta);
// Draw a shorter black line for the minute tic.
Blackline(x3, y3, x4, y4);
}
// Restore the graphics state to its original state.
graphics.restore();
}
function drawHand(centerX, centerY, length, angle, color) {
// Save the current graphics state.
graphics.save();
// Convert the angle from degrees to radians and adjust by -90 degrees (for 0 starting from top).
var theta = (angle - 90) * (Math.PI / 180);
// Calculate the end point coordinates of the hand.
var x2 = centerX + length * Math.cos(theta);
var y2 = centerY + length * Math.sin(theta);
// Begin a new path for drawing.
graphics.beginPath();
// Move the starting point of the path to the center of the clock.
graphics.moveTo(centerX, centerY);
// Draw a line from the center to the end point of the hand.
graphics.lineTo(x2, y2);
// Set the stroke color of the line.
graphics.strokeStyle = color;
// Stroke (draw) the path with the specified color.
graphics.stroke();
// Restore the graphics state to its original state.
graphics.restore();
}
function drawClock(centerX, centerY, radius) {
// Save the current graphics state.
graphics.save();
// Clear the canvas before drawing the clock
graphics.clearRect(0, 0, canvas.width, canvas.height);
drawCircle(radius, centerX, centerY, 100);
// Add the 'tics' for hours and minutes
drawTics(300, 300, 60, 240, 0.05);
// Restore the graphics state to its original state.
graphics.restore();
}
function animateClock() {
// Save the current graphics state.
graphics.save();
// Clear the canvas to prepare for drawing the clock.
graphics.clearRect(0, 0, canvas.width, canvas.height);
// Get the current date and time in the user's timezone
let d;
if (window.detectedTimezone) {
d = new Date(new Date().toLocaleString('en-US', { timeZone: window.detectedTimezone }));
} else {
d = new Date(new Date().getTime() + (userTimeZoneOffset * 60000));
}
// Calculate the angles for the clock hands based on the current time.
var milliseconds = d.getMilliseconds();
var seconds = d.getSeconds() + milliseconds / 1000;
var minutes = d.getMinutes() + seconds / 60;
var hours = d.getHours() % 12 + minutes / 60;
// Calculate the angles for each clock hand.
var secondAngle = (360 / 60) * seconds;
var minuteAngle = (360 / 60) * minutes;
var hourAngle = (360 / 12) * hours;
// Draw the clock circle.
drawClock(300, 300, 240);
// Draw the second hand.
drawHand(300, 300, 300 * 0.8, secondAngle, "red");
// Draw the minute hand.
drawHand(300, 300, 300 * 0.7, minuteAngle, "black");
// Draw the hour hand.
drawHand(300, 300, 300 * 0.5, hourAngle, "black");
// Request the next animation frame to continue the animation loop.
requestAnimationFrame(animateClock);
// Restore the graphics state to its original state.
graphics.restore();
}
function updateDateTime() {
// Use the detected timezone if available
let d;
if (window.detectedTimezone) {
d = new Date().toLocaleString('en-US', {
timeZone: window.detectedTimezone,
hour12: false,
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
} else {
// Fallback to using offset method if no timezone detected
d = new Date(new Date().getTime() + (userTimeZoneOffset * 60000));
}
// Update the content of the HTML paragraph element with the current date and time.
document.getElementById("paragraph").innerHTML = d;
}
// Initialize the clock application
async function init() {
canvas = document.getElementById("myCanvas");
graphics = canvas.getContext("2d");
// Await timezone fetching
await fetchTimeZone();
// Set up the animation loop
requestAnimationFrame(animateClock);
// Set interval to update the text clock every second
setInterval(function() {
updateDateTime();
}, 1000);
}