Reputation: 444
I'm clear doing something wrong here. All the letters print out at once. I want a typewriter effect within an HTML canvas. (Ultimately, I'd like the letters to follow a line traced within the canvas, but that's a larger puzzle.) I think the problem is in the for loop, but I'm not sure how to fix it... Any help appreciated!
<html>
<head>
<style>
canvas {
border: 2px solid #f00;
}
</style>
</head>
<label>Your message here:</label>
<br>
<input class="textBox" style="width: 50em; height: 2em;" id="userInput" />
<button id="sub_btn">Submit</button>
<body>
<canvas width="360" height="400" id="canvas"></canvas>
<script type="text/javascript">
var canvas, ctx;
function typeOut(str, startX, startY, lineHeight, padding) {
var random = Math.floor((Math.random()*100)+40);
var cursorX = startX || 0;
var cursorY = startY || 0;
var lineHeight = lineHeight || 32;
padding = padding || 10;
var i = 0;
for (i = 0; i <= str.length; i++){
var w = ctx.measureText(str.charAt(i)).width;
if(cursorX + w >= canvas.width - padding) {
cursorX = startX;
cursorY += lineHeight;
}
if (str.charAt(i) === '\n' || str.charAt(i) === '\r'){
ctx.fillText(str.charAt(i), cursorX, cursorY);
setTimeout(typeOut, 20);
cursorX = startX;
} else if (str.charAt(i) === ' '){
ctx.fillText(str.charAt(i), cursorX, cursorY);
setTimeout(typeOut, 20);
cursorX += w;
} else if (str.charAt(i) === ',' || str.charAt(i) === '.' || str.charAt(i) === '?'){
ctx.fillText(str.charAt(i), cursorX, cursorY);
setTimeout(typeOut, 220);
cursorX += w;
} else if ( str.charAt(i) === '@') {
;
setTimeout(typeOut, 300);
} else {
ctx.fillText(str.charAt(i), cursorX, cursorY);
setTimeout(typeOut, random);
cursorX += w;
}
}
}
(document.getElementById('sub_btn').onclick = function() {
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
ctx.fillStyle = '#000000';
ctx.font = '24px sans-serif';
var str = document.getElementById('userInput').value;
typeOut(str, 25, 25, 32, 10 );
})();
</script>
</body>
</html>
Upvotes: 3
Views: 341
Reputation: 36438
setTimeout()
isn't like a 'sleep' function. It doesn't pause the script. When you say:
setTimeout(typeOut, 220);
You're saying "Schedule another call to typeOut()
in 220ms, and meanwhile keep going with the for
loop as before.
You want to process a character, then call a continuation function (at the right interval) to process the next. Something like:
function typeOut(str, startX, startY, lineHeight, padding) {
var random = Math.floor((Math.random()*100)+40);
var cursorX = startX || 0;
var cursorY = startY || 0;
var lineHeight = lineHeight || 32;
padding = padding || 10;
var i = 0;
// this will be called once per character
var processNext = function() {
if (i >= str.length)
return;
var timeout = random;
var w = ctx.measureText(str.charAt(i)).width;
if(cursorX + w >= canvas.width - padding) {
cursorX = startX;
cursorY += lineHeight;
}
if (str.charAt(i) === '\n' || str.charAt(i) === '\r'){
ctx.fillText(str.charAt(i), cursorX, cursorY);
timeout = 20;
cursorX = startX;
} else if (str.charAt(i) === ' '){
ctx.fillText(str.charAt(i), cursorX, cursorY);
timeout = 20;
cursorX += w;
} else if (str.charAt(i) === ',' || str.charAt(i) === '.' || str.charAt(i) === '?'){
ctx.fillText(str.charAt(i), cursorX, cursorY);
timeout = 220;
cursorX += w;
} else if ( str.charAt(i) === '@') {
timeout = 300;
} else {
ctx.fillText(str.charAt(i), cursorX, cursorY);
cursorX += w;
}
++i;
setTimeout(processNext, timeout);
};
// now start typing
processNext();
}
Example CodePen: http://codepen.io/paulroub/pen/EDqok
Upvotes: 3