Implementing Custom Captcha Generation with HTML Canvas
HTML structure for the captcha input and canvas element:
<div class="captcha-wrapper">
<input type="text" class="captcha-field" id="captchaInput" placeholder="Enter code">
<canvas id="verification-canvas" width="120" height="40"></canvas>
</div>
CSS styling for layout and visual presentasion:
.captcha-wrapper {
display: flex;
align-items: center;
gap: 10px;
}
.captcha-field {
flex: 1;
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
#verification-canvas {
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
}
JavaScript logic for rendering randomized characters and noise on the canvas:
const CHAR_POOL = 'ABCDEFGHJKMNPQRSTWXYZ23456789'.split('');
const CAPTCHA_LENGTH = 4;
function generateCaptcha(captchaHolder) {
const canvasEl = document.getElementById('verification-canvas');
const ctx = canvasEl.getContext('2d');
const width = canvasEl.width;
const height = canvasEl.height;
ctx.clearRect(0, 0, width, height);
captchaHolder.length = 0;
for (let i = 0; i < CAPTCHA_LENGTH; i++) {
const char = CHAR_POOL[Math.floor(Math.random() * CHAR_POOL.length)];
captchaHolder.push(char.toLowerCase());
ctx.save();
const xPos = 15 + i * 25;
const yPos = 25 + Math.random() * 10;
const rotation = (Math.random() - 0.5) * 0.6;
ctx.translate(xPos, yPos);
ctx.rotate(rotation);
ctx.font = 'bold 24px Arial';
ctx.fillStyle = getRandomRgb();
ctx.fillText(char, 0, 0);
ctx.restore();
}
for (let i = 0; i < 6; i++) {
ctx.beginPath();
ctx.strokeStyle = getRandomRgb();
ctx.moveTo(Math.random() * width, Math.random() * height);
ctx.lineTo(Math.random() * width, Math.random() * height);
ctx.stroke();
}
for (let i = 0; i < 40; i++) {
ctx.beginPath();
ctx.fillStyle = getRandomRgb();
const dotX = Math.random() * width;
const dotY = Math.random() * height;
ctx.arc(dotX, dotY, 1, 0, 2 * Math.PI);
ctx.fill();
}
}
function getRandomRgb() {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
return `rgb(${r}, ${g}, ${b})`;
}