我正和一些同学一起做一个单词搜索游戏。它已经完成了,但我们面临的唯一问题是当用户决定放大或缩小时。当用户单击并在画布中拖动光标时,红线会突出显示光标下的字母。缩放后,突出显示出现在鼠标以外的其他位置。
起初,我们认为问题是由窗口滚动引起的,因为画布比屏幕大,所以我们制作了它们
您可以通过转here,放大,向下滚动一点,然后尝试突出显示一串字母来重新创建问题。
请仅包含使用Javascript的建议:没有JQuery,其他库,任何其他语言。
<html>
<head>
<title>Canvas Testing</title>
<script type="text/javascript">
var canvas,//canvas html tag
wordsCanvas,//displays words
wContext,//wordsCanvas context
context,//to edit canvas items
words = ["KING","HOMEWORK","BASEBALL","SIDEWALK","CUPCAKE","WHITEHOUSE","ISLAND","SOCCER","INDEPENDENCE","LOVE","CALCULUS","BEACH","SUMMER","PET","MICHIGAN","CANDY","WORLD","SIX","SNOW","SWEET"],//array of the words users must find
found = new Array(),
w,//width
h,//height
w1,//width of each letter (board 6 letters wide right now)
h1,//height of each letter (board 6 letters tall right now)
draw = false,//tells when the game should highlight a letter
letterPoints = new Array(),//holds the coordinates of each letter
lines = new Array(),//holds the coordinates of each line for a correct word highlighted
startLP = null,//holds the Letter object (letter, x, y) for the start of the line
endLP = null;//holds the Letter object (letter, x, y) for the end of the line
function init(){//initializes the canvas, context,w,h variables
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.height = window.innerHeight*600/630;
canvas.width = window.innerWidth*900/1380;
w=canvas.width;
h=canvas.height;
w1 = w/20;
h1 = h/20;
context.font = h1+"px Courier";
context.textAlign = "left";
context.textBaseline = "top";
wordsCanvas = document.getElementById("wordsCanvas");
wordsCanvas.height = window.innerHeight*600/630;
wordsCanvas.width = window.innerWidth*400/1380;
wContext = wordsCanvas.getContext("2d");
wContext.font = h1+"px Georgia";
wContext.textAlign = "left";
wContext.textBaseline = "top";
background();
fillWords(-1);
//add event listeners for mouse actions
canvas.addEventListener("mousedown", function(event) {
setLine("press",event);
});
canvas.addEventListener("mouseup", function(event) {
setLine("release",event);
});
canvas.addEventListener("mousemove", function(event) {
setLine("drag",event);
});
canvas.addEventListener("mouseout", function(event) {
setLine("out",event);
});
}
function fillWords(greenIndex){//displays words to search for
wContext.clearRect(0,0,300,h);
var index = 0;
if(greenIndex != -1)
{
found[found.length] = words.splice(greenIndex,1);
}
for(var i=0; i<h; i+=h1)
{
if(index<words.length)
{
wContext.fillStyle = "red";
wContext.fillText(words[index],10,i);
}
else
{
wContext.fillStyle = "green";
wContext.fillText(found[found.length-((h/h1)-index)],10,i);
}
index++;
}
wContext.fillStyle = "black";
}
function background(){//sets the background to the letters and then draws the lines that lay on correctly highlighted words words
var letterCount = 0;//counts # of letters on the board
//one string that represents all letters on the board
var backLets = "harinavesenanotheasp"+
"oobalremmusicwonsdpa"+
"momvtcalclsxvaiybaev"+
"swttysumvkingbddmrzd"+
"ahaeuyacemjtavpniche"+
"nivpnagihcimbseaceoy"+
"tthesteatkijeodchqmj"+
"ueesnodbsggmaccutsea"+
"mhmikalviabahceraqwm"+
"motislandbtcvetiwmoi"+
"eurwtenkeeeterntanra"+
"tsoolotewheewhthsekl"+
"sewroxvrarwdbaseball"+
"nehtvxjglmsadalkazqt"+
"odceetenkenstcvepcap"+
"ttaabvdlcupcakepeaxm"+
"rieqindependenceplia"+
"afbacucakehowrkdkisf"+
"chldlrowbrqmmuscqflg"+
"amerivegdsuluclacoev";
context.fillStyle = "black";
for(var y=0; y<h; y+=h1)//goes through the board and draws each letter, then stores their coordinates in the letterPoints array
{
for(var x=0; x<w; x+=w1)
{
r = y/h1 + 1;//tells the row that the letter is in
c = x/w1 + 1;//tells the column that the letter is in
temp = new Letter(backLets.charAt(letterCount),x,y,r,c);
context.fillText(temp.letter.toUpperCase(),temp.x,temp.y);
if(letterPoints.length<400)
letterPoints[letterPoints.length] = temp;
letterCount++;
}
}
/*go through lines array holding coordinates for lines that lay on correct words*/
for(var z=0; z<lines.length; z++)
{
//this if structure allows the words matching the list to be highlighted in different colors so adjacent words will not be highlighted into blocks
context.fillStyle = "lime";
var coords = lines[z];//elements of lines array are not empty but the drawLine isn't processing them
drawLine(coords[0],coords[1]);
}
}
function setLine(action, e){//sets the coordinates for the lines to be drawn
if(action == "press")
{
startLP = findNearestLP(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);//gets nearest coordenate to a click and returns a letter object with that info
if(startLP != null)
{
draw = true;
}
}
if(action == "drag")
{
//updates the last coordinates that the dragged mouse is on and draws a line to that point from the start
if(draw)
{
context.clearRect(0,0,w,h);
background();
endLP = findNearestLP(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);
context.fillStyle = "red";
drawLine(startLP, endLP);
}
}
if(action == "release" || (action == "out" && draw))
{
draw = false;
/*If a correct word is highlighted, store the start and end coordinates
else clear*/
endLP = findNearestLP(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);
//Get the letters that are highlighted by the line
if(endLP != null)
{
var word = getWord();//returns the word that was made from the start to end point by adding the characters that were highlighted
if(word != null && matchWords(word)/*This string will be replaced by a word from the list of word search targets*/)
{
lines[lines.length] = [startLP,endLP];
}
}
context.clearRect(0,0,w,h);//clears the board of any drawn lines
background();//if the line highlighted a word from the list, this method should redraw that line
if(words.length == 0)
alert("Congratulations! You win!");
}
}
//searches through the words array to see if the highlighted word is there
function matchWords(target){
if(words.indexOf(target.toUpperCase()) != -1)
{
fillWords(words.indexOf(target.toUpperCase()));
return true;
}
return false;
}
//uses coordinates from setLine() to draw the lines
function drawLine(start, end){
context.globalAlpha = 0.6;//sets transparency of lines
/*
Check up,down,left,right,diagonals
See if start and end can make a valid line
If yes, find the letters from start to end and store it as a word
*/
if(start.x == end.x && end.y>start.y)//checking down
{
context.fillRect(start.x,start.y,w1,(end.y+h1)-start.y);
}
else if(start.x == end.x && end.y<start.y)//checking up
{
context.fillRect(end.x,end.y,w1,(start.y+h1)-end.y);
}
else if(start.y == end.y && end.x>start.x)//checking left to right
{
context.fillRect(start.x,start.y,(end.x+w1)-start.x,h1);
}
else if(start.y == end.y && end.x<start.x)//checking right to left
{
context.fillRect(end.x,end.y,(start.x+w1)-end.x,h1);
}
else if(start.y > end.y && start.x < end.x && ((start.r-end.r)/(end.c-start.c))==1)//checking left to right diagonal (down to up)
{
for(var z = letterPoints.length-1; z>=0; z--)
{
var temp = letterPoints[z];
if((start.x<=temp.x && end.x>=temp.x && start.y>=temp.y && end.y<=temp.y) && ((start.y-temp.y==0 && temp.x-start.x==0) || ((start.r-temp.r)/(temp.c-start.c))==1))//((start.r-temp.r)/(temp.c-start.c))==1 means if the slope of between two points is 1
{
context.fillRect(temp.x,temp.y,w1,h1);
}
}
}
else if(start.y < end.y && start.x < end.x && ((end.r-start.r)/(end.c-start.c))==1)//checking left to right diagonal (top to bottom)
{
for(var z = 0; z<letterPoints.length; z++)
{
var temp = letterPoints[z];
if((start.x<=temp.x && end.x>=temp.x && start.y<=temp.y && end.y>=temp.y) && ((start.y-temp.y==0 && temp.x-start.x==0) || ((temp.r-start.r)/(temp.c-start.c))==1))//((temp.r-start.r)/(temp.c-start.c))==1 means if the slope of between two points is 1
{
context.fillRect(temp.x,temp.y,w1,h1);
}
}
}
else if(start.y > end.y && start.x > end.x && ((start.r-end.r)/(start.c-end.c))==1)//checking right to left diagonal (down to up)
{
for(var z = letterPoints.length-1; z>=0; z--)
{
var temp = letterPoints[z];
if((start.x>=temp.x && end.x<=temp.x && start.y>=temp.y && end.y<=temp.y) && ((start.y-temp.y==0 && start.x-temp.x==0) || ((start.r-temp.r)/(start.c-temp.c))==1))
{
context.fillRect(temp.x,temp.y,w1,h1);
}
}
}
else if(start.y < end.y && start.x > end.x && ((end.r-start.r)/(start.c-end.c))==1)//checking right diagonal (top to bottom)
{
for(var z = 0; z<letterPoints.length; z++)
{
var temp = letterPoints[z];
if((start.x>=temp.x && end.x<=temp.x && start.y<=temp.y && end.y>=temp.y) && ((start.y-temp.y==0 && start.x-temp.x==0) || ((temp.r-start.r)/(start.c-temp.c))==1))
{
context.fillRect(temp.x,temp.y,w1,h1);
}
}
}
context.globalAlpha = 1.0;//sets transparency back to 1
}
function findNearestLP(clickX,clickY){//finds the nearest letter coordinate from the user's click
for(var z = 0; z<letterPoints.length; z++)
{
var lp = letterPoints[z];
if((clickX<=lp.x+w1 && clickX>=lp.x) && (clickY<=lp.y+h1 && clickY>=lp.y))
{
return letterPoints[z];
}
}
return null;
}
function getWord()
{
var result = "";
/*
Check up,down,left,right,diagonals
See if startLP and endLP can make a valid line
If yes, find the letters from start to end and store it as a word
*/
if(startLP.x == endLP.x && endLP.y>startLP.y)//checking down
{
for(var z = 0; z<letterPoints.length; z++)
{
var temp = letterPoints[z];
if(temp.x == startLP.x && temp.y>=startLP.y && temp.y<=endLP.y)
{
result += temp.letter;
}
}
}
else if(startLP.x == endLP.x && endLP.y<startLP.y)//checking up
{
for(var z = letterPoints.length-1; z>=0; z--)
{
var temp = letterPoints[z];
if(temp.x == startLP.x && temp.y<=startLP.y && temp.y>=endLP.y)
{
result += temp.letter;
}
}
}
else if(startLP.y == endLP.y && endLP.x>startLP.x)//checking left to right
{
for(var z = 0; z<letterPoints.length; z++)
{
var temp = letterPoints[z];
if(temp.y == startLP.y && temp.x>=startLP.x && temp.x<=endLP.x)
{
result += temp.letter;
}
}
}
else if(startLP.y == endLP.y && endLP.x<startLP.x)//checking right to left
{
for(var z = letterPoints.length-1; z>=0; z--)
{
var temp = letterPoints[z];
if(temp.y == startLP.y && temp.x<=startLP.x && temp.x>=endLP.x)
{
result += temp.letter;
}
}
}
else if(startLP.y > endLP.y && startLP.x < endLP.x && ((startLP.r-endLP.r)/(endLP.c-startLP.c))==1)//checking left to right diagonal (down to up)
{
for(var z = letterPoints.length-1; z>=0; z--)
{
var temp = letterPoints[z];
if((startLP.x<=temp.x && endLP.x>=temp.x && startLP.y>=temp.y && endLP.y<=temp.y) && ((startLP.y-temp.y==0 && temp.x-startLP.x==0) || ((startLP.r-temp.r)/(temp.c-startLP.c))==1))
{
result += temp.letter;
}
}
}
else if(startLP.y < endLP.y && startLP.x < endLP.x && ((endLP.r-startLP.r)/(endLP.c-startLP.c))==1)//checking left to right diagonal (top to bottom)
{
for(var z = 0; z<letterPoints.length; z++)
{
var temp = letterPoints[z];
if((startLP.x<=temp.x && endLP.x>=temp.x && startLP.y<=temp.y && endLP.y>=temp.y) && ((startLP.y-temp.y==0 && temp.x-startLP.x==0) || ((temp.r-startLP.r)/(temp.c-startLP.c))==1))
{
result += temp.letter;
}
}
}
else if(startLP.y > endLP.y && startLP.x > endLP.x && ((startLP.r-endLP.r)/(startLP.c-endLP.c))==1)//checking right to left diagonal (down to up)
{
for(var z = letterPoints.length-1; z>=0; z--)
{
var temp = letterPoints[z];
if((startLP.x>=temp.x && endLP.x<=temp.x && startLP.y>=temp.y && endLP.y<=temp.y) && ((startLP.y-temp.y==0 && startLP.x-temp.x==0) || ((startLP.r-temp.r)/(startLP.c-temp.c))==1))
{
result += temp.letter;
}
}
}
else if(startLP.y < endLP.y && startLP.x > endLP.x && ((endLP.r-startLP.r)/(startLP.c-endLP.c))==1)//checking right diagonal (top to bottom)
{
for(var z = 0; z<letterPoints.length; z++)
{
var temp = letterPoints[z];
if((startLP.x>=temp.x && endLP.x<=temp.x && startLP.y<=temp.y && endLP.y>=temp.y) && ((startLP.y-temp.y==0 && startLP.x-temp.x==0) || ((temp.r-startLP.r)/(startLP.c-temp.c))==1))
{
result += temp.letter;
}
}
}
if(result != "")
return result;
return null;
}
//letter class
function Letter(letter,x,y){
//The letter variable is mainly used for getting the highlighted word
this.letter = letter.charAt(0);
//the x and y coordinate variables are used for drawing the highlighting line and getting the letter variable at certain coordinates
this.x = x;
this.y = y;
//the r and c variables are used to keep track of which rows and columns the letters are on. This is very helpful for drawing the highlighting line on a diagonal
this.r = r;
this.c = c;
}
</script>
</head>
<body onload="init()">
<canvas id="canvas" style="border: 1px solid #000000;"></canvas>
<canvas id="wordsCanvas" style="border: none;"></canvas>
</body>
答案 0 :(得分:0)
通过在setLine中仅使用offsetLeft和offsetTop,您不会考虑滚动。
此处的杀手武器是getBoundingClientRect,它将为您提供考虑每个方面的画布的相对位置:
function setLine(action, e){//sets the coordinates for the lines to be drawn
var bRect = canvas.getBoundingClientRect();
var relX = e.clientX - bRect.left ;
var relY = e.clientY - bRect.top;
if(action == "press")
{
startLP = findNearestLP(relX, relY);//gets nearest coordenate to a click and returns a letter object with that info
if(startLP != null)
{
draw = true;
}
}
if(action == "drag")
{
//updates the last coordinates that the dragged mouse is on and draws a line to that point from the start
if(draw)
{
context.clearRect(0,0,w,h);
background();
endLP = findNearestLP(relX, relY);
context.fillStyle = "red";
drawLine(startLP, endLP);
}
}
if(action == "release" || (action == "out" && draw))
{
draw = false;
/*If a correct word is highlighted, store the start and end coordinates
else clear*/
endLP = findNearestLP(relX, relY);
//Get the letters that are highlighted by the line
if(endLP != null)
{
var word = getWord();//returns the word that was made from the start to end point by adding the characters that were highlighted
if(word != null && matchWords(word)/*This string will be replaced by a word from the list of word search targets*/)
{
lines[lines.length] = [startLP,endLP];
}
}
context.clearRect(0,0,w,h);//clears the board of any drawn lines
background();//if the line highlighted a word from the list, this method should redraw that line
if(words.length == 0)
alert("Congratulations! You win!");
}
}