I have made a short quiz online following a tutorial, this is my first time using the canvas function. When I have typed my own questions, they appear as one line, and I am not sure how to break the lines up, in order for the question to display properly. Can anyone help?
Here is what I have so far:
<!DOCTYPE HTML>
<html>
<head>
<style>
body{
background-color: black;
}
#ccontainer{
width: 550px;
margin: 0 auto;
margin-top: 110px;
}
#myCanvas{
/*/ background: #FFF; /*/
}
</style>
<script>
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var quizbg = new Image();
var Question = new String;
var Option1 = new String;
var Option2 = new String;
var Option3 = new String;
var mx=0;
var my=0;
var CorrectAnswer = 0;
var qnumber = 0;
var rightanswers=0;
var wronganswers=0;
var QuizFinished = false;
var lock = false;
var textpos1=25;
var textpos2=145;
var textpos3=230;
var textpos4=325;
var Questions = ["Which Manchester United Player won \n the 2008 Golden Boot with 31 Goals?","At which club did Bobby Charlton start his football career?","Which year did Wayne Rooney win the BBC Young Sports Personality of the year award?"];
var Options = [["Cristiano Ronaldo","Wayne Rooney","Ryan Giggs"],["Manchester United","Manchester City","Chelsea"],["2002","2003","2004"]];
quizbg.onload = function(){
context.drawImage(quizbg, 0, 0);
SetQuestions();
}
quizbg.src = "quizbg.png";
SetQuestions = function(){
Question=Questions[qnumber];
CorrectAnswer=1+Math.floor(Math.random()*3);
if(CorrectAnswer==1){Option1=Options[qnumber][0];Option2=Options[qnumber][1];Option3=Options[qnumber][2];}
if(CorrectAnswer==2){Option1=Options[qnumber][2];Option2=Options[qnumber][0];Option3=Options[qnumber][1];}
if(CorrectAnswer==3){Option1=Options[qnumber][1];Option2=Options[qnumber][2];Option3=Options[qnumber][0];}
context.textBaseline = "middle";
context.font = "16pt sans-serif,Arial";
context.fillText(Question,20,textpos1);
context.font = "14pt sans-serif,Arial";
context.fillText(Option1,20,textpos2);
context.fillText(Option2,20,textpos3);
context.fillText(Option3,20,textpos4);
}//SetQuestions
canvas.addEventListener('click',ProcessClick,false);
function ProcessClick(ev) {
my=ev.y-canvas.offsetTop;
if(ev.y == undefined){
my = ev.pageY - canvas.offsetTop;
}
if(lock){
ResetQ();
}//if lock
else{
if(my>110 && my<180){GetFeedback(1);}
if(my>200 && my<270){GetFeedback(2);}
if(my>290 && my<360){GetFeedback(3);}
}//!lock
}//process click
GetFeedback = function(a){
if(a==CorrectAnswer){
context.drawImage(quizbg, 0,400,75,70,480,110+(90*(a-1)),75,70);
rightanswers++;
//drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
}
else{
context.drawImage(quizbg, 75,400,75,70,480,110+(90*(a-1)),75,70);
wronganswers++;
}
lock=true;
context.font = "14pt sans-serif,Arial";
context.fillText("Click again to continue",20,380);
}//get feedback
ResetQ= function(){
lock=false;
context.clearRect(0,0,550,400);
qnumber++;
if(qnumber==Questions.length){EndQuiz();}
else{
context.drawImage(quizbg, 0, 0);
SetQuestions();}
}
EndQuiz=function(){
canvas.removeEventListener('click',ProcessClick,false);
context.drawImage(quizbg, 0,0,550,90,0,0,550,400);
context.font = "20pt sans-serif,Arial";
context.fillText("You have finished the quiz!",20,100);
context.font = "16pt sans-serif,Arial";
context.fillText("Correct answers: "+String(rightanswers),20,200);
context.fillText("Wrong answers: "+String(wronganswers),20,240);
}
};
</script>
</head>
<body>
<div id="ccontainer">
<canvas id="myCanvas" width="550" height="400"></canvas>
</div>
</body>
</html>
Thanks!
You can use context.measureText to get the width of given text.
Here's a function that wraps text using context.measureText to measure each word in a sentence and wrap to a new line when the current line exceeds a given width:
A Demo: http://jsfiddle.net/m1erickson/mQFDB/
function wrapText(context, text, x, y, maxWidth, fontSize, fontFace){
var words = text.split(' ');
var line = '';
var lineHeight=fontSize;
context.font = fontSize + "px " + fontFace;
for(var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if(testWidth > maxWidth) {
context.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
}
else {
line = testLine;
}
}
context.fillText(line, x, y);
return(y);
}
You can draw your text on the canvas like this:
var lastY=wrapText(context,"Hello",20,40,100,14,"verdana");
The lastY variable holds the y-coordinate of the last line of wrapped text. Therefore you can begin new text at lastY plus some padding:
lastY=wrapText(context,"World",20,lastY+20,100,14,"verdana");
This pattern lets you make text-wrapped paragraphs down the canvas (or in your case questions and multiple choice answers down the canvas).
Related
Lately I learned a bit about strange attractors, and I created the following programm in JS:
var ctx, clock, width, height, pixSize;
var x,y,a,b,c,d;
window.onload = function(){
start();
};
function start(random=true){
window.cancelAnimationFrame(clock);
if(random){
a = 6*Math.random()-3;
b = 6*Math.random()-3;
c = 2*Math.random()-0.5;
d = 2*Math.random()-0.5;
}
canvasSetup();
clearCanvas();
x = Math.random()-Math.random();
y = Math.random()-Math.random();
clock = requestAnimationFrame(main);
}
function save(){
var text = JSON.stringify({
a:a,
b:b,
c:c,
d:d
});
window.prompt("Copy to clipboard: Ctrl+C", text);
}
function load(){
var input = JSON.parse(window.prompt("Import Save:"));
a = input.a;
b = input.b;
c = input.c;
d = input.d;
start(false);
}
function canvasSetup(){
canvas = document.getElementById('canvas');
width = window.innerWidth-5;
height = window.innerHeight-5;
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
var min = Math.min(width,height);
var scale = min/4;
ctx.translate(width/2, height/2);
ctx.scale(scale, scale);
pixSize = 1/scale/2;
ctx.globalCompositeOperation = "lighter";
}
function clearCanvas(){
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0,width,height);
ctx.restore();
}
function main(){
for(var i=0;i<10000;i++){
var xnew = Math.sin(y*b)+c*Math.sin(x*b);
var ynew = Math.sin(x*a)+d*Math.sin(y*a);
x = xnew;
y = ynew;
plot(x,y,"rgb(50,5,1)");
}
clock = requestAnimationFrame(main);
}
function plot(x,y,color="white"){
ctx.fillStyle = color;
ctx.fillRect(x,-y,pixSize,pixSize);
}
body {
background-color: black;
color: white;
font-family: Consolas;
font-size: 13px;
margin: 0;
padding: 0;
}
#buttons{
position: absolute;
top: 0;
left: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Strange Attractor</title>
<link rel="stylesheet" href="style.css">
<script src="rules.js"></script>
<script src="script.js"></script>
</head>
<body>
<div align="center">
<canvas id="canvas"></canvas>
</div>
<div id="buttons">
<button onclick="start()">New Attractor</button><br>
<button onclick="save()">Save</button><br>
<button onclick="load()">Load</button>
</div>
</body>
</html>
It's taking 4 random Parameters (a,b,c,d) and uses the formular
var xnew = Math.sin(y*b)+c*Math.sin(x*b);
var ynew = Math.sin(x*a)+d*Math.sin(y*a);
x = xnew;
y = ynew;
for the new point. In some cases this indeed creates a fancy strange sttractor:
But in other cases I only get a single line or a few points. Is there a simple way to look at the parameters and find out, if the attrator they create will be strange?
I know, that I could save a bunch of values, compare them with each other and test in that way, if the picture might be intresting, but I'd love a different solution...
I hope you can help :)
EDIT:
To look at speccific values you can simply use the save and load buttons in the js sketch above...
I've been working on a simple matching puzzle game for a little while now. Currently I have been able to have a countdown time and the number of matching tiles displayed as a text and I'm trying to create one for the best time completed (basically how fast the person completed the puzzle). However whenever I try to create it the text never displays.I noticed while writing the code that if I where to place the variable "txt" followed by a "." the autocomplete box will appear with .text as an available option so I would get "txt.text". I do not however get that option when writing the bestTimeTxt variable which is what I am using to display the time. I'm not sure what I have done wrong, here is my code.
<!DOCTYPE html>
<html>
<head>
<title>Recipe: Drawing a square</title>
<script src="easel.js"></script>
<script type="text/javascript">
var canvas;
var stage;
var squareSide = 70;
var squareOutline = 5;
var max_rgb_color_value = 255;
var gray = Graphics.getRGB(20, 20, 20);
var placementArray = [];
var tileClicked;
var timeAllowable;
var totalMatchesPossible;
var matchesFound;
var txt;
var bestTime;
var bestTimeTxt;
var matchesFoundText;
var squares;
function init() {
var rows = 5;
var columns = 6;
var squarePadding = 10;
canvas = document.getElementById('myCanvas');
stage = new Stage(canvas);
var numberOfTiles = rows*columns;
matchesFound = 0;
timeAllowable = 5;
bestTime = 0
txt = new Text(timeAllowable, "30px Monospace", "#000");
txt.textBaseline = "top"; // draw text relative to the top of the em box.
txt.x = 500;
txt.y = 0;
bestTimeTxt = new Text(bestTime, "30px Monospace", "#000");
bestTimeTxt.textBaseLine = "top";
bestTimeTxt.x = 300;
bestTimeTxt.y = 0;
stage.addChild(txt);
stage.addChild(bestTimeTxt);
squares = [];
totalMatchesPossible = numberOfTiles/2;
Ticker.init();
Ticker.addListener(window);
Ticker.setPaused(false);
matchesFoundText = new Text("Pairs Found: "+matchesFound+"/"+totalMatchesPossible, "30px Monospace", "#000");
matchesFoundText.textBaseline = "top"; // draw text relative to the top of the em box.
matchesFoundText.x = 500;
matchesFoundText.y = 40;
stage.addChild(matchesFoundText);
setPlacementArray(numberOfTiles);
for(var i=0;i<numberOfTiles;i++){
var placement = getRandomPlacement(placementArray);
if (i % 2 === 0){
var color = randomColor();
}
var square = drawSquare(gray);
square.color = color;
square.x = (squareSide+squarePadding) * (placement % columns);
square.y = (squareSide+squarePadding) * Math.floor(placement / columns);
squares.push(square);
stage.addChild(square);
square.cache(0, 0, squareSide + squarePadding, squareSide + squarePadding);
square.onPress = handleOnPress;
stage.update();
};
}
function drawSquare(color) {
var shape = new Shape();
var graphics = shape.graphics;
graphics.setStrokeStyle(squareOutline);
graphics.beginStroke(gray);
graphics.beginFill(color);
graphics.rect(squareOutline, squareOutline, squareSide, squareSide);
return shape;
}
function randomColor(){
var color = Math.floor(Math.random()*255);
var color2 = Math.floor(Math.random()*255);
var color3 = Math.floor(Math.random()*255);
return Graphics.getRGB(color, color2, color3)
}
function setPlacementArray(numberOfTiles){
for(var i = 0;i< numberOfTiles;i++){
placementArray.push(i);
}
}
function getRandomPlacement(placementArray){
randomNumber = Math.floor(Math.random()*placementArray.length);
return placementArray.splice(randomNumber, 1)[0];
}
function handleOnPress(event){
var tile = event.target;
tile.graphics.beginFill(tile.color).rect(squareOutline, squareOutline, squareSide, squareSide);
if(!!tileClicked === false || tileClicked === tile){
tileClicked = tile;
tileClicked.updateCache("source-overlay");
}else{
if(tileClicked.color === tile.color && tileClicked !== tile){
tileClicked.visible = false;
tile.visible = false;
matchesFound++;
matchesFoundText.text = "Pairs Found: "+matchesFound+"/"+totalMatchesPossible;
if (matchesFound===totalMatchesPossible){
gameOver(true);
}
}else{
tileClicked.graphics.beginFill(gray).rect(squareOutline, squareOutline, squareSide, squareSide);
}
tileClicked.updateCache("source-overlay");
tile.updateCache("source-overlay");
tileClicked = tile;
}
stage.update();
}
function tick() {
secondsLeft = Math.floor((timeAllowable-Ticker.getTime()/1000));
txt.text = secondsLeft;
bestTimeTxt.text = "test";
if (secondsLeft <= 0){
gameOver(false);
}
stage.update();
}
function gameOver(win){
Ticker.setPaused(true);
for(var i=0;i<squares.length;i++){
squares[i].graphics.beginFill(squares[i].color).rect(5, 5, 70, 70);
squares[i].onPress = null;
if (win === false){
squares[i].uncache();
}
}
var replayParagraph = document.getElementById("replay");
replayParagraph.innerHTML = "<a href='#' onClick='history.go(0);'>Play Again?</a>";
if (win === true){
matchesFoundText.text = "You win!"
}else{
txt.text = secondsLeft + "... Game Over";
}
}
function replay(){
init();
}
</script>
</head>
<body onload="init()">
<header id="header">
<p id="replay"></p>
</header>
<canvas id="myCanvas" width="960" height="400"></canvas>
</body>
</html>
Apparently the issue I was having was that the x and y position of the text was causing it to appear behind everything else.
I'm currently working on a small tile matching game and have made it so that each time you complete the game the variable "bestTime" will store the amount of time you took to complete the session. The variable "bestTimeTxt" will then take the value and display it in text. After you have completed a session a link will appear allowing you to start again. I have put the new text
bestTimeTxt = new Text("Best Time: " + bestTime , "30px Monospace", "#000");
bestTimeTxt.textBaseLine = "top";
bestTimeTxt.x = 500;
bestTimeTxt.y = 100;
outside of the init() function so it shouldn't keep resetting I'm not sure what I am supposed to do as every combination i could think of isn't working.
here is my full code.
I'm also using easeljs for this game
<!DOCTYPE html>
<html>
<head>
<title>Recipe: Drawing a square</title>
<script src="easel.js"></script>
<script type="text/javascript">
var canvas;
var stage;
var squareSide = 70;
var squareOutline = 5;
var max_rgb_color_value = 255;
var gray = Graphics.getRGB(20, 20, 20);
var placementArray = [];
var tileClicked;
var timeAllowable;
var totalMatchesPossible;
var matchesFound;
var txt;
var bestTime = 0;
var bestTimeTxt;
var matchesFoundText;
var squares;
var startingTime;
bestTimeTxt = new Text("Best Time: " + bestTime , "30px Monospace", "#000");
bestTimeTxt.textBaseLine = "top";
bestTimeTxt.x = 500;
bestTimeTxt.y = 100;
function init() {
var rows = 5;
var columns = 6;
var squarePadding = 10;
canvas = document.getElementById('myCanvas');
stage = new Stage(canvas);
var numberOfTiles = rows*columns;
matchesFound = 0;
timeAllowable = 500;
startingTime = timeAllowable;
txt = new Text(timeAllowable, "30px Monospace", "#000");
txt.textBaseline = "top"; // draw text relative to the top of the em box.
txt.x = 500;
txt.y = 0;
stage.addChild(bestTimeTxt);
stage.addChild(txt);
squares = [];
totalMatchesPossible = numberOfTiles/2;
Ticker.init();
Ticker.addListener(window);
Ticker.setPaused(false);
matchesFoundText = new Text("Pairs Found: "+matchesFound+"/"+totalMatchesPossible, "30px Monospace", "#000");
matchesFoundText.textBaseline = "top"; // draw text relative to the top of the em box.
matchesFoundText.x = 500;
matchesFoundText.y = 40;
stage.addChild(matchesFoundText);
setPlacementArray(numberOfTiles);
for(var i=0;i<numberOfTiles;i++){
var placement = getRandomPlacement(placementArray);
if (i % 2 === 0){
var color = randomColor();
}
var square = drawSquare(gray);
square.color = color;
square.x = (squareSide+squarePadding) * (placement % columns);
square.y = (squareSide+squarePadding) * Math.floor(placement / columns);
squares.push(square);
stage.addChild(square);
square.cache(0, 0, squareSide + squarePadding, squareSide + squarePadding);
square.onPress = handleOnPress;
stage.update();
};
}
function drawSquare(color) {
var shape = new Shape();
var graphics = shape.graphics;
graphics.setStrokeStyle(squareOutline);
graphics.beginStroke(gray);
graphics.beginFill(color);
graphics.rect(squareOutline, squareOutline, squareSide, squareSide);
return shape;
}
function randomColor(){
var color = Math.floor(Math.random()*255);
var color2 = Math.floor(Math.random()*255);
var color3 = Math.floor(Math.random()*255);
return Graphics.getRGB(color, color2, color3)
}
function setPlacementArray(numberOfTiles){
for(var i = 0;i< numberOfTiles;i++){
placementArray.push(i);
}
}
function getRandomPlacement(placementArray){
randomNumber = Math.floor(Math.random()*placementArray.length);
return placementArray.splice(randomNumber, 1)[0];
}
function handleOnPress(event){
var tile = event.target;
tile.graphics.beginFill(tile.color).rect(squareOutline, squareOutline, squareSide, squareSide);
if(!!tileClicked === false || tileClicked === tile){
tileClicked = tile;
tileClicked.updateCache("source-overlay");
}else{
if(tileClicked.color === tile.color && tileClicked !== tile){
tileClicked.visible = false;
tile.visible = false;
matchesFound++;
matchesFoundText.text = "Pairs Found: "+matchesFound+"/"+totalMatchesPossible;
if (matchesFound===totalMatchesPossible){
gameOver(true);
}
}else{
tileClicked.graphics.beginFill(gray).rect(squareOutline, squareOutline, squareSide, squareSide);
}
tileClicked.updateCache("source-overlay");
tile.updateCache("source-overlay");
tileClicked = tile;
}
stage.update();
}
function tick() {
secondsLeft = Math.floor((timeAllowable-Ticker.getTime()/1000));
txt.text = secondsLeft;
;
if (secondsLeft <= 0){
gameOver(false);
}
stage.update();
}
function gameOver(win){
Ticker.setPaused(true);
for(var i=0;i<squares.length;i++){
squares[i].graphics.beginFill(squares[i].color).rect(5, 5, 70, 70);
squares[i].onPress = null;
if (win === false){
squares[i].uncache();
}
}
var replayParagraph = document.getElementById("replay");
replayParagraph.innerHTML = "<a href='#' onClick='history.go(0);'>Play Again?</a>";
if (win === true){
matchesFoundText.text = "You win!"
if((startingTime - secondsLeft) > bestTime)
{
bestTime = startingTime - secondsLeft;
bestTimeTxt.text = "Best Time: " + bestTime;
}
}
else
{
txt.text = secondsLeft + "... Game Over";
}
}
function replay(){
init();
}
</script>
</head>
<body onload="init()">
<header id="header">
<p id="replay"></p>
</header>
<canvas id="myCanvas" width="960" height="400"></canvas>
</body>
</html>
In your code, inside gameover method, I see you are using history.go(0) on play again link.
Technically, history.go(0) means to refresh the page and all your variables no matter the scope are set to the initial values.
If you want to retain the best score for the session and continue, use the replay method instead of history.
Updated Code :
replayParagraph.innerHTML = "<a href='#' onClick='replay();'>Play Again?</a>";
This problem is (probably) not caused by the width/height being in the CSS, because it isn't. (How to avoid HTML Canvas auto-stretching)
When trying to make rage inputs to demonstrate an issue I was having, I found that when using range inputs it acted stranger. It seems to be representing a larger number than what I'm passing in.
Please check my code out and tell me what's causing all this. http://codepen.io/Magnesium/pen/wMwwgx
var engine = function(canvas) { // Trying to make a game engine when the problems started
this.canvas = canvas.getContext("2d");
this.defaultColor = "#FF0000";
this.clearCanvas = function() { // Clears canvas
this.canvas.clearRect(0, 0, canvas.width, canvas.height);
};
this.square = function(x, y, size, color) { // Makes a square. I don't see any problems, but if the error is caused by me it would probably be here
if (color == undefined) color = this.defaultColor;
this.canvas.fillStyle = color;
this.canvas.fillRect(x, y, x + size, y + size);
};
}
var canvas = document.getElementById("canvas");
var rangeX = document.getElementById("x");
var rangeY = document.getElementById("y");
var size = document.getElementById("sz");
var outX = document.getElementById("ox");
var outY = document.getElementById("oy");
var outSize = document.getElementById("osz");
var out = document.getElementById("out");
var enjin = new engine(canvas); // New engine
var defalt = false;
var src = document.getElementById("src");
setInterval(function() { // Called ~30 times a second
enjin.clearCanvas();
defalt ? enjin.square(50, 50, 50) : enjin.square(rangeX.value, rangeY.value, size.value);
defalt ? out.innerHTML = "enjin.square(50, 50, 50);" : out.innerHTML = "enjin.square("+rangeX.value+", "+rangeY.value+", "+size.value+");";
defalt ? src.innerHTML = "Using in-code values" : src.innerHTML = "Using slider values";
outX.innerHTML = rangeX.value;
outY.innerHTML = rangeY.value;
outSize.innerHTML = size.value;
}, 30);
The values you're passing to enjin.square are strings. You need to parse them to int:
enjin.square(parseInt(rangeX.value), parseInt(rangeY.value), parseInt(size.value));
Here's a working example:
var engine = function(canvas) { // Trying to make a game engine when the problems started
this.canvas = canvas.getContext("2d");
this.defaultColor = "#FF0000";
this.clearCanvas = function() { // Clears canvas
this.canvas.clearRect(0, 0, canvas.width, canvas.height);
};
this.square = function(x, y, size, color) { // Makes a square. I don't see any problems, but if the error is caused by me it would probably be here
if (color == undefined) color = this.defaultColor;
this.canvas.fillStyle = color;
this.canvas.fillRect(x, y, x + size, y + size);
};
}
var canvas = document.getElementById("canvas");
var rangeX = document.getElementById("x");
var rangeY = document.getElementById("y");
var size = document.getElementById("sz");
var outX = document.getElementById("ox");
var outY = document.getElementById("oy");
var outSize = document.getElementById("osz");
var out = document.getElementById("out");
var enjin = new engine(canvas); // New engine
var defalt = false;
var src = document.getElementById("src");
setInterval(function() { // Called ~30 times a second
enjin.clearCanvas();
defalt ? enjin.square(50, 50, 50) : enjin.square(parseInt(rangeX.value), parseInt(rangeY.value), parseInt(size.value));
defalt ? out.innerHTML = "enjin.square(50, 50, 50);" : out.innerHTML = "enjin.square(" + rangeX.value + ", " + rangeY.value + ", " + size.value + ");";
defalt ? src.innerHTML = "Using in-code values" : src.innerHTML = "Using slider values";
outX.innerHTML = rangeX.value;
outY.innerHTML = rangeY.value;
outSize.innerHTML = size.value;
}, 30);
#canvas {
border: 1px solid black;
}
<canvas id='canvas' width='400' height='400'></canvas>
<br />X
<input type='range' id='x' /><span id='ox'></span>
<br />Y
<input type='range' id='y' /><span id='oy'></span>
<br />Size
<input type='range' id='sz' /><span id='osz'></span>
<br /><span id='out'></span>
<br />
<button onclick='defalt = !defalt;'>Default value toggle</button>
<span id='src'></span>
And a updated pen.
I have made a short quiz online following a tutorial, this is my first time using the canvas function. When I have typed my own questions, they appear as one line, and I am not sure how to break the lines up, in order for the question to display properly. Can anyone help?
Here is what I have so far:
<!DOCTYPE HTML>
<html>
<head>
<style>
body{
background-color: black;
}
#ccontainer{
width: 550px;
margin: 0 auto;
margin-top: 110px;
}
#myCanvas{
/*/ background: #FFF; /*/
}
</style>
<script>
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var quizbg = new Image();
var Question = new String;
var Option1 = new String;
var Option2 = new String;
var Option3 = new String;
var mx=0;
var my=0;
var CorrectAnswer = 0;
var qnumber = 0;
var rightanswers=0;
var wronganswers=0;
var QuizFinished = false;
var lock = false;
var textpos1=25;
var textpos2=145;
var textpos3=230;
var textpos4=325;
var Questions = ["Which Manchester United Player won \n the 2008 Golden Boot with 31 Goals?","At which club did Bobby Charlton start his football career?","Which year did Wayne Rooney win the BBC Young Sports Personality of the year award?"];
var Options = [["Cristiano Ronaldo","Wayne Rooney","Ryan Giggs"],["Manchester United","Manchester City","Chelsea"],["2002","2003","2004"]];
quizbg.onload = function(){
context.drawImage(quizbg, 0, 0);
SetQuestions();
}
quizbg.src = "quizbg.png";
SetQuestions = function(){
Question=Questions[qnumber];
CorrectAnswer=1+Math.floor(Math.random()*3);
if(CorrectAnswer==1){Option1=Options[qnumber][0];Option2=Options[qnumber][1];Option3=Options[qnumber][2];}
if(CorrectAnswer==2){Option1=Options[qnumber][2];Option2=Options[qnumber][0];Option3=Options[qnumber][1];}
if(CorrectAnswer==3){Option1=Options[qnumber][1];Option2=Options[qnumber][2];Option3=Options[qnumber][0];}
context.textBaseline = "middle";
context.font = "16pt sans-serif,Arial";
context.fillText(Question,20,textpos1);
context.font = "14pt sans-serif,Arial";
context.fillText(Option1,20,textpos2);
context.fillText(Option2,20,textpos3);
context.fillText(Option3,20,textpos4);
}//SetQuestions
canvas.addEventListener('click',ProcessClick,false);
function ProcessClick(ev) {
my=ev.y-canvas.offsetTop;
if(ev.y == undefined){
my = ev.pageY - canvas.offsetTop;
}
if(lock){
ResetQ();
}//if lock
else{
if(my>110 && my<180){GetFeedback(1);}
if(my>200 && my<270){GetFeedback(2);}
if(my>290 && my<360){GetFeedback(3);}
}//!lock
}//process click
GetFeedback = function(a){
if(a==CorrectAnswer){
context.drawImage(quizbg, 0,400,75,70,480,110+(90*(a-1)),75,70);
rightanswers++;
//drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
}
else{
context.drawImage(quizbg, 75,400,75,70,480,110+(90*(a-1)),75,70);
wronganswers++;
}
lock=true;
context.font = "14pt sans-serif,Arial";
context.fillText("Click again to continue",20,380);
}//get feedback
ResetQ= function(){
lock=false;
context.clearRect(0,0,550,400);
qnumber++;
if(qnumber==Questions.length){EndQuiz();}
else{
context.drawImage(quizbg, 0, 0);
SetQuestions();}
}
EndQuiz=function(){
canvas.removeEventListener('click',ProcessClick,false);
context.drawImage(quizbg, 0,0,550,90,0,0,550,400);
context.font = "20pt sans-serif,Arial";
context.fillText("You have finished the quiz!",20,100);
context.font = "16pt sans-serif,Arial";
context.fillText("Correct answers: "+String(rightanswers),20,200);
context.fillText("Wrong answers: "+String(wronganswers),20,240);
}
};
</script>
</head>
<body>
<div id="ccontainer">
<canvas id="myCanvas" width="550" height="400"></canvas>
</div>
</body>
</html>
Thanks!
You can use context.measureText to get the width of given text.
Here's a function that wraps text using context.measureText to measure each word in a sentence and wrap to a new line when the current line exceeds a given width:
A Demo: http://jsfiddle.net/m1erickson/mQFDB/
function wrapText(context, text, x, y, maxWidth, fontSize, fontFace){
var words = text.split(' ');
var line = '';
var lineHeight=fontSize;
context.font = fontSize + "px " + fontFace;
for(var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if(testWidth > maxWidth) {
context.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
}
else {
line = testLine;
}
}
context.fillText(line, x, y);
return(y);
}
You can draw your text on the canvas like this:
var lastY=wrapText(context,"Hello",20,40,100,14,"verdana");
The lastY variable holds the y-coordinate of the last line of wrapped text. Therefore you can begin new text at lastY plus some padding:
lastY=wrapText(context,"World",20,lastY+20,100,14,"verdana");
This pattern lets you make text-wrapped paragraphs down the canvas (or in your case questions and multiple choice answers down the canvas).