我正在尝试将the code in this answer(运行问题解答片段及其答案)与下面的其余部分进行整合,以允许用户向下滚动sideButtons
选择菜单通过悬停在选择菜单的底部或顶部区域。但是,我不确定如何编写requestAnimationFrame
函数来使用它来处理对象结构的其余部分或放置它的位置。
附在sideButtons
' mouseMove
eventListener
功能有两个hitTest
' {#1}}'和' lowerHoverBoxHitTest(x, y)
'。这些检测选择菜单的上半部分或下半部分是否悬停在上面。如果是这样,upperHoverBoxHitTest(x, y)
应相应递增,以便根据选择的hoverAmount
向上或向下推sideButtons
。但是,这部分 - 必须(我认为)发生在hoverBox
函数中 - 在上面的代码中不起作用。
如果仍然不清楚动画应该如何工作,请参阅上面附带的链接。应该很清楚它目前没有正常工作......任何帮助将不胜感激。
requestAnimationFrame

var buttonTypeSelection = document.getElementById('languageSelection');
var initialButtonType;
var buttonRanges = {'1-10': [1,2,3,4,5,6,7,8,9,10],
'One to Ten': ['One','Two','Three','Four','Five',
'Six','Seven','Eight','Nine','Ten'],
'0000-1010': ['0001','0010','0011','0100','0101',
'0110','0111','1000','1001','1010']};
var buttonTypeIndex = {'1-10': 1, 'One to Ten': 2, '0000-1010': 3};
Object.keys(buttonRanges).forEach(function(buttonType) {
buttonTypeSelection.options[buttonTypeSelection.options.length] = new Option(buttonType, buttonTypeIndex[buttonType]);
}, buttonRanges);
buttonTypeSelection.options.selectedIndex = 1; // set to page source language's code
initialButtonType=buttonRanges[Object.keys(buttonRanges)[buttonTypeSelection.options.selectedIndex]];
function Game (elementID,width,height){
this.elementID = elementID;
this.element = document.getElementById(elementID);
this.width = width;
this.height = height;
this.palette = {
color1:'#fff',
color2:'#000',
color3:'#9F3A9B',
color4:'#a84ea5',
color5:'#b56ab2',
color6:'#bf7dbd',
color7:'#d5a8d2'
};
this.element.style.width = width + 'px';
this.element.style.height= height + 'px';
this.element.style.border='solid thin ' + this.palette.color2;
this.element.style.display= 'block';
//this.element.style.margin='1em auto';
this.element.style.background=this.palette.color3;
this.buttonType=buttonRanges[buttonTypeSelection.options[buttonTypeSelection.selectedIndex].text];
this.hoverAmount = 0;
this.overTypes = {none:0, lower:1, raise:2}
this.overBox = 0;
this.overDist = 0;
this.initialGame();
}
Game.prototype.initialGame = function(){
this.canvas = document.createElement("canvas");
this.canvas.width = this.width;
this.canvas.height = this.height;
this.element.appendChild(this.canvas);
this.initialSideButtons();
this.initialTitle();
this.initialBoard();
this.initialFooter();
// initial selection
this.sideButtons.select(this.sideButtons.buttons[0]);
this.resize(this.width,this.height);
this.render();
this.attachEvents();
}
Game.prototype.attachEvents = function(){
var element = this.element;
var getX = function(evt){return evt.offsetX || evt.layerX || (evt.clientX - element.offsetLeft);};
var getY = function(evt){return evt.offsetY || evt.layerY || (evt.clientY - element.offsetTop);};
var game = this;
this.element.addEventListener('mousemove',function(evt){
game.hover(getX(evt),getY(evt));
if (game.sideButtons.lowerHoverBoxHitTest(game.hoverX, game.hoverY)) {
game.overBox=game.overTypes.raise;
} else if (game.sideButtons.upperHoverBoxHitTest(game.hoverX, game.hoverY)) {
game.overBox=game.overTypes.lower;
} else {
game.overBox=game.overTypes.none;
}
game.render();
});
this.element.addEventListener('click',function(evt){
game.sideButtons.click();
game.render();
});
}
Game.prototype.onSelect = function(button){
this.selected = button;
};
Game.prototype.hover=function(x,y){
this.hoverX = x;
this.hoverY = y;
};
Game.prototype.initialBoard = function(){
var game = this;
var Board = function(){
this.left = 0;
this.top = 0;
this.width = 0;
this.height = 0;
};
Board.prototype.render = function(ctx){
if(game.selected){
var shapeWidth = this.width/3;
ctx.fillStyle = game.palette.color1;
ctx.strokeStyle = game.palette.color1;
var fontSize = 14;
ctx.font = 'bold '+ fontSize +'px Noto Sans';
ctx.textAlign='center';
ctx.lineWidth=8;
ctx.lineJoin = 'round';
ctx.strokeRect(this.left + this.width/2 - (shapeWidth/2),this.height/2-(shapeWidth/2) + this.top,shapeWidth,shapeWidth);
ctx.fillText(game.selected.text,this.left + this.width/2,this.height/2 + this.top );
}
};
this.board = new Board();
};
Game.prototype.initialSideButtons = function(){
var game = this;
var ButtonBar =function(text){
this.text = text;
this.left = 0;
this.top = 0;
this.width = 1;
this.height= 1;
this.selected=false;
};
ButtonBar.prototype.hitTest=function(x,y){
return (this.left < x) && (x < (this.left + this.width)) &&
(this.top <y) && (y < (this.top + this.height));
};
ButtonBar.prototype.getColor=function(){
var hovered = this.hitTest(game.hoverX,game.hoverY);
if(this.selected){
if(hovered)
{
return game.palette.color7;
}
return game.palette.color6;
}
if(hovered){
return game.palette.color5;
}
return game.palette.color4;
};
ButtonBar.prototype.render = function(ctx){
var fontSize = 14;
ctx.fillStyle = this.getColor();
ctx.fillRect(this.left, this.top, this.width, this.height);
ctx.fillStyle = game.palette.color1;
ctx.textAlign = 'left';
ctx.font ='bold '+ fontSize +'px Noto Sans';
ctx.fillText(this.text,this.left + 10,this.top+ this.height/2);
};
var SideButtons = function(){
this.buttons = [];
this.width = 1;
this.height= 1;
this.left=1;
this.top=1;
};
SideButtons.prototype.lowerHoverBoxHitTest = function(x, y) {
game.overDist = y - (game.title.height + game.footer.top) - game.hoverScrollSize;
return (x >= this.width) && (x <= game.width) &&
(y >= ((game.title.height + game.footer.top) - game.hoverScrollSize)) && (y <= (game.title.height + game.footer.top));
}
SideButtons.prototype.upperHoverBoxHitTest = function(x, y) {
game.overDist = game.hoverScrollSize - y;
return (x>=this.width) && (x <= game.width) &&
(y >= game.title.height) && (y <= (game.title.height+game.hoverScrollSize));
}
SideButtons.prototype.render = function(ctx){
if(!this.buttons.length){
return;
}
var height = (this.height / this.buttons.length)/0.45;
for(var i=0;i<this.buttons.length;i++){
var btn = this.buttons[i];
btn.left = this.left;
btn.top = i * height + this.top;
btn.width = this.width;
btn.height = height;
this.buttons[i].render(ctx);
}
};
SideButtons.prototype.click = function() {
var current = null;
for(var i=0;i<this.buttons.length;i++){
var btn = this.buttons[i];
if(btn.hitTest(game.hoverX,game.hoverY)) {
this.select(btn);
break;
}
}
};
SideButtons.prototype.select = function(btn) {
for(var i=0; i<this.buttons.length; i++) {
this.buttons[i].selected = false;
}
btn.selected=true;
game.onSelect(btn);
};
SideButtons.prototype.refreshShapes = function() {
this.buttons = [];
for (var buttonIndex=1; buttonIndex<=10; buttonIndex++) {
this.buttons.push(new ButtonBar('Button ' + game.buttonType[buttonIndex]));
}
}
this.sideButtons = new SideButtons();
for (var buttonIndex=1; buttonIndex<=10; buttonIndex++) {
this.sideButtons.buttons.push(new ButtonBar('Button ' + game.buttonType[buttonIndex]));
}
};
Game.prototype.initialTitle = function(){
var Title = function(value,width,height){
this.value=value;
this.width = width;
this.height= height;
};
var game = this;
Title.prototype.render=function(ctx){
var k = 2;
var fontSize = this.height / k;
ctx.fillStyle=game.palette.color1;
ctx.fillRect(0,0,this.width,this.height);
ctx.font='bold '+ fontSize +'px Noto Sans'; // check
ctx.fillStyle=game.palette.color3;
ctx.textAlign='center';
ctx.fillText(this.value,this.width/2,this.height - fontSize/2);
};
this.title = new Title('Test',this.width,this.height / 10);
}
Game.prototype.initialFooter = function(){
var Footer = function(){
this.width = 1;
this.height= 1;
this.left=0;
this.top=0;
}
var game = this;
Footer.prototype.render = function(ctx){
ctx.fillStyle = game.palette.color5;
ctx.fillRect(this.left,this.top,this.width,this.height);
};
this.footer = new Footer();
};
Game.prototype.resetCanvas = function() {
this.canvas.width = this.width;
this.canvas.height = this.height;
};
Game.prototype.render = function () {
var that = this;
that._render();
}
Game.prototype._render = function() {
this.resetCanvas();
var context = this.canvas.getContext('2d');
this.sideButtons.render(context);
this.title.render(context);
this.board.render(context);
this.footer.render(context);
};
Game.prototype.resize = function (width,height){
this.width = width;
this.height= height;
this.element.style.width = width + 'px';
this.element.style.height= height+ 'px';
this.title.height = this.height / 14;
this.title.width = this.width;
this.footer.height = this.title.height;
this.footer.width = this.width;
this.footer.top = this.height - this.footer.height;
this.footer.left = 0;
this.board.top = this.title.height;
this.board.left = 0;
this.board.width = this.width / 2;
this.board.height= this.height - this.title.height - this.footer.height;
this.sideButtons.left= this.board.width;
this.sideButtons.top = this.board.top + this.hoverAmount;
this.sideButtons.width = this.width - this.board.width;
this.sideButtons.height = this.board.height;
this.maxSpeed = this.height*(5/500);
this.shapeSize = this.height*(30/500);
this.hoverScrollSize = this.height*(100/500);
this.render();
};
var game = new Game('game',window.innerWidth -50,window.innerWidth * 2/3);
window.addEventListener('resize', function(){
game.resize(window.innerWidth -50,window.innerWidth * 2/3);
});
buttonTypeSelection.addEventListener('change', function() {
game.buttonType=buttonRanges[buttonTypeSelection.options[buttonTypeSelection.selectedIndex].text];
var selectedIndex = game.sideButtons.buttons.indexOf(game.selected);
game.sideButtons.refreshShapes();
game.selected = game.sideButtons.buttons[selectedIndex];
game.render();
});
requestAnimationFrame(() => {
game.resize(window.innerWidth - 50, window.innerWidth * 2/3);
requestAnimationFrame(mainLoop); // start main loop
});
function mainLoop() {
if (game.overBox !== game.overTypes.none) {
game.hoverAmount += game.overDist/game.hoverScrollSize * (game.overBox === game.overTypes.lower ? game.maxSpeed : -game.maxSpeed);
var bottom = (game.height - (game.title.height + game.footer.height) + (game.sideButtons.buttons.length * game.shapeSize));
// game.hoverAmount = (game.hoverAmount > 0) ? 0 : (game.hoverAmount < bottom) ? bottom : game.hoverAmount;
game.resize(window.innerWidth - 50, window.innerWidth * 2/3);
}
requestAnimationFrame(mainLoop);
}
&#13;
答案 0 :(得分:2)
这不是关于requestionAnimationFrame
,而是关于计算滚动的逻辑(滚动偏移,命中区域的命中)。
upperBoxHitTest
和lowerBoxHitTest
。mainloop
内的计算充满了问题。你不能只复制一个代码片段,做一些简单的替换,并希望它能正常工作。你应该弄清楚它是如何工作的,它的内部逻辑,你不会害怕通过更复杂的实现来推动它。
因此,我建议您再次检查代码,并尝试找出代码有什么问题。在你取得一些进展或实际上无法解决之前,你可以查看我的代码是如何工作的。如果是后来的情况,你可能需要阅读更多有关逻辑思维,问题分析和编程方法的书籍。
祝你好运!
代码片段stackoverflow的iframe区域非常小,您应该在此处查看https://jsbin.com/bucisupugu/edit?js,output。
const btnTypeSelectElem = document.getElementById('languageSelection');
const buttonRanges = {
'1-10': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'One to Ten': ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten'],
'0000-1010': ['0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010']
};
const buttonTypeIndex = {
'1-10': 1,
'One to Ten': 2,
'0000-1010': 3
};
Object.keys(buttonRanges)
.forEach(function (buttonType) {
btnTypeSelectElem.add(new Option(buttonType, buttonTypeIndex[buttonType]));
});
btnTypeSelectElem.options.selectedIndex = 1; // set to page source language's code
const initialButtonType = buttonRanges[Object.keys(buttonRanges)[btnTypeSelectElem.options.selectedIndex]];
class Game {
constructor(elementID, width, height) {
this.elementID = elementID;
this.element = document.getElementById(elementID);
this.width = width;
this.height = height;
this.palette = {
color1: '#fff',
color2: '#000',
color3: '#9F3A9B',
color4: '#a84ea5',
color5: '#b56ab2',
color6: '#bf7dbd',
color7: '#d5a8d2'
};
this.element.style.width = `${width}px`;
this.element.style.height = `${height}px`;
this.element.style.border = `solid thin ${this.palette.color2}`;
this.element.style.display = 'block';
//this.element.style.margin='1em auto';
this.element.style.background = this.palette.color3;
this.buttonRange = buttonRanges[btnTypeSelectElem.options[btnTypeSelectElem.selectedIndex].text];
this.scrollTop = 0;
this.overTypes = {
none: 0,
lower: 1,
raise: 2
};
this.overBox = 0;
// overDist have different meanings for upper box and lower box
// for upper: y offset to the top of hover scroll zone
// for lower: y offset to the bottom of hover scroll zone
// and in fact it's actually for sidebuttons container, coz the sidebuttons is
// the simulated scroll container
this.overDist = 0;
this.initiateGame();
}
initiateGame() {
this.canvas = document.createElement("canvas");
this.canvas.width = this.width;
this.canvas.height = this.height;
this.element.appendChild(this.canvas);
this.initiateSideButtons();
this.initiateTitle();
this.initiateBoard();
this.initiateFooter();
// initial selection
this.sideButtons.select(this.sideButtons.buttons[0]);
this.resize(this.width, this.height);
this.render();
this.attachEvents();
}
attachEvents() {
const element = this.element;
const getX = function (evt) {
return evt.offsetX || evt.layerX || evt.clientX - element.offsetLeft;
};
const getY = function (evt) {
return evt.offsetY || evt.layerY || evt.clientY - element.offsetTop;
};
this.element.addEventListener('mousemove', (evt) => {
this.hover(getX(evt), getY(evt));
if (this.sideButtons.upperHoverBoxHitTest(this.hoverX, this.hoverY)) {
game.overDist = game.hoverScrollZoneSize - (this.hoverY - game.title.height);
this.overBox = this.overTypes.lower;
} else if (this.sideButtons.lowerHoverBoxHitTest(this.hoverX, this.hoverY)) {
game.overDist = game.hoverScrollZoneSize - (game.footer.top - this.hoverY);
this.overBox = this.overTypes.raise;
} else {
game.overDist = 0
this.overBox = this.overTypes.none;
}
this.render();
});
this.element.addEventListener('click', (evt) => {
this.sideButtons.click();
this.render();
});
}
onSelect(button) {
this.selected = button;
}
hover(x, y) {
this.hoverX = x;
this.hoverY = y;
}
initiateBoard() {
const game = this;
class Board {
constructor() {
this.left = 0;
this.top = 0;
this.width = 0;
this.height = 0;
}
render(ctx) {
if (game.selected) {
const shapeWidth = this.width / 3;
ctx.fillStyle = game.palette.color1;
ctx.strokeStyle = game.palette.color1;
const fontSize = 14;
ctx.font = `bold ${fontSize}px Noto Sans`;
ctx.textAlign = 'center';
ctx.lineWidth = 8;
ctx.lineJoin = 'round';
ctx.strokeRect(this.left + this.width / 2 - shapeWidth / 2, this.height / 2 - shapeWidth / 2 + this.top, shapeWidth, shapeWidth);
ctx.fillText(game.selected.text, this.left + this.width / 2, this.height / 2 + this.top);
}
}
}
this.board = new Board();
}
initiateSideButtons() {
const game = this;
class ButtonBar {
constructor(text) {
this.text = text;
this.left = 0;
this.top = 0;
this.width = 1;
this.height = 1;
this.selected = false;
}
hitTest(x, y) {
return this.left < x &&
x < this.left + this.width &&
this.top < y &&
y < this.top + this.height;
}
getColor() {
const hovered = this.hitTest(game.hoverX, game.hoverY);
if (this.selected) {
if (hovered) {
return game.palette.color7;
}
return game.palette.color6;
}
if (hovered) {
return game.palette.color5;
}
return game.palette.color4;
}
render(ctx) {
const fontSize = 14;
ctx.fillStyle = this.getColor();
ctx.fillRect(this.left, this.top, this.width, this.height);
ctx.fillStyle = game.palette.color1;
ctx.textAlign = 'left';
ctx.font = `bold ${fontSize}px Noto Sans`;
ctx.fillText(this.text, this.left + 10, this.top + this.height / 2);
}
}
class SideButtons {
constructor() {
this.buttons = [];
this.width = 1;
this.height = 1;
this.left = 1;
this.top = 1;
}
upperHoverBoxHitTest(x, y) {
return x >= this.left &&
x <= this.left + this.width &&
y >= game.title.height &&
y <= game.title.height + game.hoverScrollZoneSize;
}
lowerHoverBoxHitTest(x, y) {
return x >= this.left &&
x <= this.left + this.width &&
y >= game.footer.top - game.hoverScrollZoneSize &&
y <= game.footer.top;
}
render(ctx) {
if (!this.buttons.length) {
return;
}
const height = this.height / this.buttons.length / 0.45;
for (let i = 0; i < this.buttons.length; i++) {
const btn = this.buttons[i];
btn.left = this.left;
btn.top = i * height + this.top;
btn.width = this.width;
btn.height = height;
this.buttons[i].render(ctx);
}
}
click() {
const current = null;
for (let i = 0; i < this.buttons.length; i++) {
const btn = this.buttons[i];
if (btn.hitTest(game.hoverX, game.hoverY)) {
this.select(btn);
break;
}
}
}
select(btn) {
for (let i = 0; i < this.buttons.length; i++) {
this.buttons[i].selected = false;
}
btn.selected = true;
game.onSelect(btn);
}
refreshShapes() {
this.buttons = [];
// note: fix an out-of-index bug here
for (let buttonIndex = 0; buttonIndex < 10; buttonIndex++) {
this.buttons.push(new ButtonBar(`Button ${game.buttonRange[buttonIndex]}`));
}
}
}
this.sideButtons = new SideButtons();
// note: fix an out-of-index bug here
for (let buttonIndex = 0; buttonIndex < 10; buttonIndex++) {
this.sideButtons.buttons.push(new ButtonBar(`Button ${game.buttonRange[buttonIndex]}`));
}
}
initiateTitle() {
class Title {
constructor(value, width, height) {
this.value = value;
this.width = width;
this.height = height;
}
render(ctx) {
const k = 2;
const fontSize = this.height / k;
ctx.fillStyle = game.palette.color1;
ctx.fillRect(0, 0, this.width, this.height);
ctx.font = `bold ${fontSize}px Noto Sans`; // check
ctx.fillStyle = game.palette.color3;
ctx.textAlign = 'center';
ctx.fillText(this.value, this.width / 2, this.height - fontSize / 2);
}
}
const game = this;
this.title = new Title('Test', this.width, this.height / 10);
}
initiateFooter() {
class Footer {
constructor() {
this.width = 1;
this.height = 1;
this.left = 0;
this.top = 0;
}
render(ctx) {
ctx.fillStyle = game.palette.color5;
ctx.fillRect(this.left, this.top, this.width, this.height);
}
}
const game = this;
this.footer = new Footer();
}
resetCanvas() {
this.canvas.width = this.width;
this.canvas.height = this.height;
}
render() {
const that = this;
that._render();
}
_render() {
this.resetCanvas();
const context = this.canvas.getContext('2d');
this.sideButtons.render(context);
this.title.render(context);
this.board.render(context);
this.footer.render(context);
}
resize(width, height) {
this.width = width;
this.height = height;
this.element.style.width = `${width}px`;
this.element.style.height = `${height}px`;
this.title.height = this.height / 14;
this.title.width = this.width;
this.footer.height = this.title.height;
this.footer.width = this.width;
this.footer.top = this.height - this.footer.height;
this.footer.left = 0;
this.board.top = this.title.height;
this.board.left = 0;
this.board.width = this.width / 2;
this.board.height = this.height - this.title.height - this.footer.height;
this.sideButtons.left = this.board.width;
this.sideButtons.top = this.board.top + this.scrollTop;
this.sideButtons.width = this.width - this.board.width;
this.sideButtons.height = this.board.height;
this.maxSpeed = this.height * (5 / 500);
this.shapeSize = this.height * (30 / 500);
// hover scroll zone is that area when mouse hovers on it will trigger scrolling behavior
this.hoverScrollZoneSize = this.height * (100 / 500);
this.render();
}
}
const game = new Game('game', window.innerWidth - 50, window.innerWidth * 2 / 3);
window.addEventListener('resize', function () {
game.resize(window.innerWidth - 50, window.innerWidth * 2 / 3);
});
btnTypeSelectElem.addEventListener('change', function () {
game.buttonRange = buttonRanges[btnTypeSelectElem.options[btnTypeSelectElem.selectedIndex].text];
const selectedIndex = game.sideButtons.buttons.indexOf(game.selected);
game.sideButtons.refreshShapes();
game.selected = game.sideButtons.buttons[selectedIndex];
game.render();
});
requestAnimationFrame(() => {
game.resize(window.innerWidth - 50, window.innerWidth * 2 / 3);
requestAnimationFrame(mainLoop); // start main loop
});
function mainLoop() {
if (game.overBox !== game.overTypes.none) {
game.scrollTop += game.overDist / game.hoverScrollZoneSize * (game.overBox === game.overTypes.lower ? game.maxSpeed : -game.maxSpeed);
const bottom = -game.sideButtons.height;
game.scrollTop = (game.scrollTop > 0) ? 0 : (game.scrollTop < bottom) ? bottom : game.scrollTop;
game.resize(window.innerWidth - 50, window.innerWidth * 2 / 3);
}
requestAnimationFrame(mainLoop);
}
<!doctype html>
<html lang="en">
<body>
<div id='game'></div>
<div class="styled-select">
<select id="languageSelection"></select>
</div>
<script type='text/javascript' src='game.js'></script>
</body>
</html>
答案 1 :(得分:0)
将Game.render方法的主体移动到Game._render私有方法中,并使用requestAnimationFrame调用render方法内的_render方法。
GameState
var buttonTypeSelection = document.getElementById('languageSelection');
var initialButtonType;
var buttonRanges = {'1-10': [1,2,3,4,5,6,7,8,9,10],
'One to Ten': ['One','Two','Three','Four','Five',
'Six','Seven','Eight','Nine','Ten'],
'0000-1010': ['0001','0010','0011','0100','0101',
'0110','0111','1000','1001','1010']};
var buttonTypeIndex = {'1-10': 1, 'One to Ten': 2, '0000-1010': 3};
Object.keys(buttonRanges).forEach(function(buttonType) {
buttonTypeSelection.options[buttonTypeSelection.options.length] = new Option(buttonType, buttonTypeIndex[buttonType]);
}, buttonRanges);
buttonTypeSelection.options.selectedIndex = 1; // set to page source language's code
initialButtonType=buttonRanges[Object.keys(buttonRanges)[buttonTypeSelection.options.selectedIndex]];
function Game (elementID,width,height){
this.elementID = elementID;
this.element = document.getElementById(elementID);
this.width = width;
this.height = height;
this.palette = {
color1:'#fff',
color2:'#000',
color3:'#9F3A9B',
color4:'#a84ea5',
color5:'#b56ab2',
color6:'#bf7dbd',
color7:'#d5a8d2'
};
this.element.style.width = width + 'px';
this.element.style.height= height + 'px';
this.element.style.border='solid thin ' + this.palette.color2;
this.element.style.display= 'block';
//this.element.style.margin='1em auto';
this.element.style.background=this.palette.color3;
this.initialGame();
}
Game.prototype.initialGame = function(){
this.canvas = document.createElement("canvas");
this.canvas.width = this.width;
this.canvas.height = this.height;
this.element.appendChild(this.canvas);
this.initialTitle();
this.initialSideButtons();
this.initialBoard();
this.initialFooter();
// initial selection
this.sideButtons.select(this.sideButtons.buttons[0]);
this.resize(this.width,this.height);
this.render();
this.attachEvents();
}
Game.prototype.attachEvents = function(){
var element = this.element;
var getX = function(evt){return evt.offsetX || evt.layerX || (evt.clientX - element.offsetLeft);};
var getY = function(evt){return evt.offsetY || evt.layerY || (evt.clientY - element.offsetTop);};
var game = this;
this.element.addEventListener('mousemove',function(evt){
game.hover(getX(evt),getY(evt));
game.render();
});
this.element.addEventListener('click',function(evt){
game.sideButtons.click();
game.render();
});
}
Game.prototype.onSelect = function(button){
this.selected = button;
};
Game.prototype.hover=function(x,y){
this.hoverX = x;
this.hoverY = y;
};
Game.prototype.initialBoard = function(){
var game = this;
var Board = function(){
this.left = 0;
this.top = 0;
this.width =0;
this.height=0;
};
Board.prototype.render = function(ctx){
if(game.selected){
var shapeWidth = this.width/3;
ctx.fillStyle = game.palette.color1;
ctx.strokeStyle = game.palette.color1;
var fontSize = 14;
ctx.font = 'bold '+ fontSize +'px Noto Sans';
ctx.textAlign='center';
ctx.lineWidth=8;
ctx.lineJoin = 'round';
ctx.strokeRect(this.left + this.width/2 - (shapeWidth/2),this.height/2-(shapeWidth/2) + this.top,shapeWidth,shapeWidth);
ctx.fillText(game.selected.text,this.left + this.width/2,this.height/2 + this.top );
}
};
this.board = new Board();
};
Game.prototype.initialSideButtons = function(){
var game = this;
var ButtonBar =function(text){
this.text = text;
this.left = 0;
this.top = 0;
this.width = 1;
this.height= 1;
this.selected=false;
};
ButtonBar.prototype.hitTest=function(x,y){
return (this.left < x) && (x < (this.left + this.width)) &&
(this.top <y) && (y < (this.top + this.height));
};
ButtonBar.prototype.getColor=function(){
var hovered = this.hitTest(game.hoverX,game.hoverY);
if(this.selected){
if(hovered)
{
return game.palette.color7;
}
return game.palette.color6;
}
if(hovered){
return game.palette.color5;
}
return game.palette.color4;
};
ButtonBar.prototype.render = function(ctx){
var fontSize = 14;
ctx.fillStyle = this.getColor();
ctx.fillRect(this.left,this.top,this.width,this.height);
ctx.fillStyle = game.palette.color1;
ctx.textAlign = 'left';
ctx.font ='bold '+ fontSize +'px Noto Sans';
ctx.fillText(this.text,this.left + 10,this.top+ this.height/2);
};
var SideButtons = function(){
this.buttons = [];
this.width = 1;
this.height= 1;
this.left=1;
this.top=1;
};
SideButtons.prototype.render = function(ctx){
if(!this.buttons.length){
return;
}
var height = (this.height / this.buttons.length)/0.45;
for(var i=0;i<this.buttons.length;i++){
var btn = this.buttons[i];
btn.left = this.left;
btn.top = i * height + this.top;
btn.width = this.width;
btn.height = height;
this.buttons[i].render(ctx);
}
};
SideButtons.prototype.click = function(){
var current = null;
for(var i=0;i<this.buttons.length;i++){
var btn = this.buttons[i];
if( btn.hitTest(game.hoverX,game.hoverY))
{
this.select(btn);
break;
}
}
};
SideButtons.prototype.select = function(btn)
{
for(var i=0;i<this.buttons.length;i++)
{
this.buttons[i].selected = false;
}
btn.selected=true;
game.onSelect(btn);
};
this.sideButtons = new SideButtons();
for (var buttonNumber=1; buttonNumber<=10; buttonNumber++) {
this.sideButtons.buttons.push(new ButtonBar('Button '+buttonNumber));
}
};
Game.prototype.initialTitle = function(){
var Title = function(value,width,height){
this.value=value;
this.width = width;
this.height= height;
};
var game = this;
Title.prototype.render=function(ctx){
var k = 2;
var fontSize = this.height / k;
ctx.fillStyle=game.palette.color1;
ctx.fillRect(0,0,this.width,this.height);
ctx.font='bold '+ fontSize +'px Noto Sans'; // check
ctx.fillStyle=game.palette.color3;
ctx.textAlign='center';
ctx.fillText(this.value,this.width/2,this.height - fontSize/2);
};
this.title = new Title('Test',this.width,this.height / 10);
}
Game.prototype.initialFooter = function(){
var Footer = function(){
this.width = 1;
this.height= 1;
this.left=0;
this.top=0;
}
var game = this;
Footer.prototype.render = function(ctx){
ctx.fillStyle = game.palette.color5;
ctx.fillRect(this.left,this.top,this.width,this.height);
};
this.footer = new Footer();
};
Game.prototype.resetCanvas = function(){
this.canvas.width = this.width;
this.canvas.height = this.height;
};
Game.prototype.render = function (){
var that = this;
requestAnimationFrame(function(){that._render();});
}
Game.prototype._render = function(){
this.resetCanvas();
var context = this.canvas.getContext('2d');
this.title.render(context);
this.sideButtons.render(context);
this.board.render(context);
this.footer.render(context);
};
Game.prototype.resize = function (width,height){
this.width = width;
this.height= height;
this.element.style.width = width + 'px';
this.element.style.height= height+ 'px';
this.title.height = this.height / 14;
this.title.width = this.width;
this.footer.height = this.title.height;
this.footer.width = this.width;
this.footer.top = this.height - this.footer.height;
this.footer.left = 0;
this.board.top = this.title.height;
this.board.left = 0;
this.board.width = this.width / 2;
this.board.height= this.height - this.title.height - this.footer.height;
this.sideButtons.left= this.board.width;
this.sideButtons.top = this.board.top;
this.sideButtons.width = this.width - this.board.width;
this.sideButtons.height = this.board.height;
this.render();
};
var game = new Game('game',window.innerWidth -50,window.innerWidth * 2/3);
window.addEventListener('resize', function(){
game.resize(window.innerWidth -50,window.innerWidth * 2/3);
});