You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, clockScale = 0.7, themeColor = '#ffffff', faceOpacity = 0.4) {
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
const ctx = canvas.getContext('2d');
// A flag to allow stopping the animation if the caller needs to clear memory
let isRunning = true;
canvas.stopClockAnimation = () => { isRunning = false; };
function drawHand(position, length, width, color) {
ctx.beginPath();
ctx.lineWidth = width;
ctx.lineCap = "round";
ctx.strokeStyle = color;
ctx.moveTo(canvas.width / 2, canvas.height / 2);
ctx.lineTo(
canvas.width / 2 + Math.cos(position) * length,
canvas.height / 2 + Math.sin(position) * length
);
ctx.stroke();
}
function drawClock() {
if (!isRunning) return;
// Reset shadows for background rendering to avoid performance hit and visual bugs
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// Draw the original image as the background
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Determine base scaling relative to image dimensions
const minDim = Math.min(canvas.width, canvas.height);
const radius = (minDim / 2) * clockScale;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// Setup shadows to give the clock depth against the image
ctx.shadowColor = 'rgba(0, 0, 0, 0.6)';
ctx.shadowBlur = Math.max(2, radius * 0.05);
ctx.shadowOffsetX = Math.max(1, radius * 0.01);
ctx.shadowOffsetY = Math.max(1, radius * 0.01);
// Draw clock face background (Dark semi-transparent circle)
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
ctx.fillStyle = `rgba(0, 0, 0, ${faceOpacity})`;
ctx.fill();
// Draw outer ring
ctx.lineWidth = Math.max(2, radius * 0.02);
ctx.strokeStyle = themeColor;
ctx.stroke();
// Draw Minute & Hour Ticks
for (let i = 0; i < 60; i++) {
const angle = (i * Math.PI) / 30;
const isHourTick = i % 5 === 0;
const tickLength = isHourTick ? radius * 0.1 : radius * 0.05;
const tickWidth = isHourTick ? radius * 0.03 : radius * 0.015;
ctx.beginPath();
ctx.lineWidth = Math.max(1, tickWidth);
ctx.strokeStyle = themeColor;
ctx.moveTo(
centerX + Math.cos(angle) * (radius - tickLength),
centerY + Math.sin(angle) * (radius - tickLength)
);
ctx.lineTo(
centerX + Math.cos(angle) * radius,
centerY + Math.sin(angle) * radius
);
ctx.stroke();
}
// Draw hour numbers (12, 3, 6, 9)
ctx.font = `bold ${radius * 0.25}px Arial`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = themeColor;
const textOffset = radius * 0.68;
// Text requires slight position tweaking since y is inverted on canvas compared to typical cartesian mapping
ctx.fillText("12", centerX, centerY - textOffset);
ctx.fillText("3", centerX + textOffset, centerY);
ctx.fillText("6", centerX, centerY + textOffset);
ctx.fillText("9", centerX - textOffset, centerY);
// Fetch current localized time
const now = new Date();
const hour = now.getHours();
const minute = now.getMinutes();
const second = now.getSeconds();
const ms = now.getMilliseconds();
// Calculate mapped angles (Subtract PI / 2 to shift the 0-degree point from 3 o'clock to 12 o'clock)
const secPos = ((second + (ms / 1000)) * Math.PI) / 30 - Math.PI / 2; // Smooth second hand
const minPos = ((minute + (second / 60)) * Math.PI) / 30 - Math.PI / 2;
const hrPos = (((hour % 12) + (minute / 60)) * Math.PI) / 6 - Math.PI / 2;
// Draw Hour Hand
drawHand(hrPos, radius * 0.45, Math.max(2, radius * 0.05), themeColor);
// Draw Minute Hand
drawHand(minPos, radius * 0.65, Math.max(1.5, radius * 0.035), themeColor);
// Draw Second Hand (Red for high visibility)
drawHand(secPos, radius * 0.8, Math.max(1, radius * 0.015), '#ff4444');
// Draw tail of Second Hand wrapping backwards slightly
drawHand(secPos + Math.PI, radius * 0.15, Math.max(1, radius * 0.015), '#ff4444');
// Draw Center Pin
ctx.beginPath();
ctx.arc(centerX, centerY, radius * 0.04, 0, 2 * Math.PI);
ctx.fillStyle = '#ff4444';
ctx.fill();
// Loop animation matching the screen's refresh rate
requestAnimationFrame(drawClock);
}
// Start the clock animation loop
drawClock();
return canvas;
}
Apply Changes