【问题标题】:HTML Canvas & JavaScript - Selection Menu - Setting Initial and Sustaining Current SelectionHTML Canvas & JavaScript - 选择菜单 - 设置初始和维持当前选择
【发布时间】:2017-07-12 15:43:16
【问题描述】:

在下面的 HTML 画布中,我有一个选择菜单,它根据所选内容触发在其旁边绘制图像(下例中的数字 1-5)。 JavaScript 使用伪对象方法来存储/操作在画布上绘制的图像。除了EventListener 附加到画布之外,还有一个EventListener 附加到整个窗口,当窗口大小改变时,它会在严格的纵横比内调整画布的大小。

我目前遇到的问题是,当 EventListener 被触发时(当窗口大小改变时),选择被清除。要在下面的示例中复制这一点,您必须在全屏模式下运行代码 sn-p 并更改浏览器窗口的大小。相反,我希望在窗口(以及相应的画布')大小更改后保持当前选择。我尝试将当前选择分配给一个变量,但我只能让它留下一个静态选择,其中 onHover 动画不起作用。

此外,与此相关,我正在尝试设置在第一次画布绘制时选择的初始选择,直到选择其他选项之一。在这种情况下,当脚本最初加载时,我希望自动选择/显示数字 1 及其对应的图像,直到做出新的选择。同样,将其分配为initialSelection 变量或独立调用makeCurvedRect 会留下静态选择,我的意思是curvedRect(图像)不是动画onHover

我非常不确定如何实现这些结果,因此我们将不胜感激。为大量代码道歉,但我无法压缩它。

var c=document.getElementById('game'),
    rect = c.getBoundingClientRect(),
		ctx=c.getContext('2d');

c.width  = window.innerWidth;
c.height = (2/3)*c.width;

numberImages = ['https://i.stack.imgur.com/TZIUz.png','https://i.stack.imgur.com/6beTF.png','https://i.stack.imgur.com/wZk2H.png','https://i.stack.imgur.com/1K743.png','https://i.stack.imgur.com/jMMmQ.png'];

var curvedRect = function(number, x, y, w, h) {
    this.text = number.toString();
	this.img = new Image();
	this.img.src=numberImages[number-1];
	this.x = x;
	this.y = y;
	this.w = w;
	this.h = h;
	this.hovered = false;
	this.clicked = false;
	this.visible = false;
}

var selected;
curvedRect.prototype.makeCurvedRect = function() {
	var delta=0, theta=0;
	if (this.hovered) {
		delta = (c.height*(3/500));
		theta = -0.01;
		shadowColor = '#000000';
		shadowBlur = 20;
		shadowOffsetX = 5;
		shadowOffsetY = 5;
	} else {
		delta = 0;
		theta = 0;
		shadowColor = '#9F3A9B';
		shadowBlur = 0;
		shadowOffsetX = 0;
		shadowOffsetY = 0;
	}
	var x = this.x-delta;
	var y = this.y-delta;
	var w = this.w+(2*delta);
	var h = this.h+(2*delta);
	var cornerRounder = (c.height*(10/500))
	ctx.rotate(theta);
	ctx.beginPath();
	ctx.lineWidth='12';
	ctx.strokeStyle='white';
	ctx.moveTo(x+cornerRounder, y);
	ctx.lineTo(x+w-cornerRounder, y);
	ctx.quadraticCurveTo(x+w, y, x+w, y+cornerRounder);
	ctx.lineTo(x+w, y+h-cornerRounder);
	ctx.quadraticCurveTo(x+w, y+h, x+w-cornerRounder, y+h);
	ctx.lineTo(x+cornerRounder, y+h);
	ctx.quadraticCurveTo(x, y+h, x, y+h-cornerRounder);
	ctx.lineTo(x, y+cornerRounder);
	ctx.quadraticCurveTo(x, y, x+cornerRounder, y);
	ctx.shadowColor = shadowColor;
	ctx.shadowBlur = shadowBlur;
	ctx.shadowOffsetX = shadowOffsetX;
	ctx.shadowOffsetY = shadowOffsetY;
	ctx.stroke();
	ctx.shadowBlur = 0;
	ctx.shadowOffsetX = 0;
	ctx.shadowOffsetY = 0;
	ctx.drawImage(this.img, x+(c.width*(2.5/750)), y+(c.height*(2.5/500)), w-cornerRounder/2, h-cornerRounder/2);
	ctx.rotate(-theta);
}

curvedRect.prototype.hitTest = function(x, y) {
	return (x >= this.x) && (x <= (this.w+this.x)) && (y >= this.y) && (y <= (this.h+this.y));
}

var selectionForMenu = function(id, text, y) {
	this.id = id;
	this.text = text;
	this.y = y;
	this.hovered = false;
	this.clicked = false;
	this.lastClicked = false;
	this.visible = true;
}

function makeTextForSelected(text, y) {
	ctx.font='bold '+(c.height*(12/500))+'px Noto Sans'; // check
	ctx.fillStyle='white';
	ctx.textAlign='center';
	ctx.fillText(text, (c.width*(200/750)), y);
}

selectionForMenu.prototype.makeSelection = function() {
	ctx.globalAlpha=0.75;
	var fillColor='#A84FA5';
	if (this.hovered) {
		if (this.clicked) {
			if (this.lastClicked) {
				fillColor='#E4C7E2';
				makeTextForSelected(this.text, c.height*(375/500));
			} else {
				fillColor='#D5A9D3';
			}
		} else if (this.lastClicked) {
			fillColor='#D3A4D0';
			makeTextForSelected(this.text, c.height*(375/500));
		} else {
			fillColor='#BA74B7';
		}
	} else if (this.lastClicked) {
		fillColor='#C78DC5';
		makeTextForSelected(this.text, c.height*(375/500));
	} else {
		fillColor='#A84FA5';
	}
	ctx.beginPath();
	ctx.fillStyle=fillColor;
	ctx.fillRect(c.width*(400/750), this.y, c.width*(350/750), c.height*(100/500))
	ctx.stroke();

	ctx.font=c.height*(10/500)+'px Noto Sans';
	ctx.fillStyle='white';
	ctx.textAlign='left';
	ctx.fillText(this.text, c.width*(410/750), this.y+(c.height*(38/500)));

	ctx.globalAlpha=1;
}

selectionForMenu.prototype.hitTest = function(x, y) {
	return (x >= (c.width*(400/750)) && (x <= c.width) && (y >= this.y) &&
	(y <= (this.y+(c.height*(100/500))) && !((x >= c.width*(400/750) && (y > c.height*(450/500))))));
}

var Paint = function(element) {
	this.element = element;
	this.shapes = [];
}

Paint.prototype.addShape = function(shape) {
	this.shapes.push(shape);
}

Paint.prototype.render = function() {

	ctx.clearRect(0, 0, this.element.width, this.element.height);

	for (var i=0; i<this.shapes.length; i++) {
		try {
			this.shapes[i].makeSelection();
		}
		catch(err) {}
		try {
			if(this.shapes[i].lastClicked == true) {
				this.shapes[i].rect.makeCurvedRect();
			}
		}
		catch(err) {}
	}

	ctx.beginPath();
	ctx.fillStyle='white';
	ctx.fillRect(0, 0, c.width, (c.height*(25/500)));
	ctx.stroke();

	ctx.beginPath();
	ctx.fillStyle='#BC77BA';
	ctx.fillRect(0, (c.height*(450/500)), c.width, (c.height*(50/500)));
	ctx.stroke();

	ctx.font='bold '+(c.height*(10/500))+'px Noto Sans';
	ctx.fillStyle='#9F3A9B';
	ctx.textAlign='center';
	ctx.fillText('Test', (c.width*(365/750)), (c.height*(17/500)));
}

Paint.prototype.setHovered = function(shape) {
	for (var i=0; i<this.shapes.length; i++) {
		this.shapes[i].hovered = this.shapes[i] == shape;
	}
	this.render();
}

Paint.prototype.setClicked = function(shape) {
	for (var i=0; i<this.shapes.length; i++) {
		this.shapes[i].clicked = this.shapes[i] == shape;
	}
	this.render();
}

Paint.prototype.setUnclicked = function(shape) {
	for (var i=0; i<this.shapes.length; i++) {
		if (shape.constructor.name==this.shapes[i].constructor.name) {
			this.shapes[i].clicked = false;
		 	if (shape instanceof selectionForMenu) {
				this.shapes[i].lastClicked = this.shapes[i] == shape;
				if (this.shapes[i].lastClicked == true) {
					this.shapes[i].rect.visible = true;
				} else {
					this.shapes[i].rect.visible = false;
				}
			}
		}
	}
	this.render();
}

Paint.prototype.select = function(x, y) {
	for (var i=this.shapes.length-1; i >= 0; i--) {
		if (this.shapes[i].visible == true && this.shapes[i].hitTest(x, y)) {
			return this.shapes[i];
		}
	}
	return null
}

var numbers = [1,2,3,4,5];
var paint = new Paint(c);
var selection = [];
for (var i=0; i<numbers.length; i++) {
	selection.push(new selectionForMenu(i+1, numbers[i], c.height*(25/500)+(c.height*((i*100)/500))));
}
for (var i=0; i<numbers.length; i++) {
	var img = new curvedRect(i+1, (c.width*(112.5/750)), (c.height*(100/500)), (c.height*(175/500)), (c.height*(175/500)));
	paint.addShape(img)
	selection[i].rect = img;
}

for (var i=0; i<numbers.length; i++) {
	paint.addShape(selection[i])
}

paint.render();

var clickedShape, clickIndex=0;
function mouseDown(event) {
	var x = (event.pageX-rect.left)/(rect.right-rect.left)*c.width;
	var y = (event.pageY-rect.top)/(rect.bottom-rect.top)*c.height;
	var shape = paint.select(x, y);
	if (shape instanceof selectionForMenu) {
		if (clickIndex==0) {
			clickedShape=shape;
			clickIndex=1;
		} else if (clickIndex==1) {
			clickIndex=0;
		}
	}
	paint.setClicked(shape);
}

function mouseUp(event) {
	var x = (event.pageX-rect.left)/(rect.right-rect.left)*c.width;
	var y = (event.pageY-rect.top)/(rect.bottom-rect.top)*c.height;
	var shape = paint.select(x, y);
	if (clickedShape instanceof selectionForMenu) {
		if (x>c.width*(400/750) && y>c.height*(25/500) && y<c.height*(450/500)) {
			paint.setUnclicked(shape);
		} else if (shape && !(shape instanceof selectionForMenu)) {
			paint.setUnclicked(shape);
		}
	}
}

function mouseMove(event) {
	var x = (event.pageX-rect.left)/(rect.right-rect.left)*c.width;
	var y = (event.pageY-rect.top)/(rect.bottom-rect.top)*c.height;
	var shape = paint.select(x, y);

	paint.setHovered(shape);
}

function paintCanvas() {
  c.width  = window.innerWidth;
  c.height = (2/3)*c.width;
  ctx=c.getContext('2d');
  rect = c.getBoundingClientRect();

  paint = new Paint(c);
  selection = [];
  for (var i=0; i<numbers.length; i++) {
    selection.push(new selectionForMenu(i+1, numbers[i], c.height*(25/500)+(c.height*((i*100)/500))));
  }
  for (var i=0; i<numbers.length; i++) {
    var img = new curvedRect(i+1, (c.width*(112.5/750)), (c.height*(100/500)), (c.height*(175/500)), (c.height*(175/500)));
    paint.addShape(img)
    selection[i].rect = img;
  }

  for (var i=0; i<numbers.length; i++) {
    paint.addShape(selection[i])
  }
  paint.render();
}

paintCanvas();

window.addEventListener('resize', paintCanvas);
c.addEventListener('mousedown', mouseDown);
c.addEventListener('mouseup', mouseUp);
c.addEventListener('mousemove', mouseMove);
canvas {
  z-index: -1;
  margin: 1em auto;
  border: 1px solid black;
  display: block;
  background: #9F3A9B;
}
<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>uTalk Demo</title>
	<link rel='stylesheet' type='text/css' href='wordpractice.css' media='screen'></style>
</head>
<body>
	<div id='container'>
		<canvas id="game"></canvas>
	</div>
  <script type='text/javascript' src='scaleStack.js'></script>
</body>
</html>

【问题讨论】:

    标签: javascript html events canvas


    【解决方案1】:

    您必须(在您的代码中)创建一次绘制类,

    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 ;
    		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();
    
    	var btn1 = new ButtonBar('Button 1');
    	var btn2 = new ButtonBar('Button 2');
    	var btn3 = new ButtonBar('Button 3');
    	var btn4 = new ButtonBar('Button 4');
    
    	this.sideButtons.buttons.push(btn1);
    	this.sideButtons.buttons.push(btn2);
    	this.sideButtons.buttons.push(btn3);
    	this.sideButtons.buttons.push(btn4);
    
    };
    
    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(){
    	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  - 250;//or -> 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);
    });
    	<div id='container'>
    		<div id="game"></div>
    	</div>

    【讨论】:

    • 完美!谢谢。我唯一不确定的是在game 首次加载时设置初始选择。
    • 并且,与此相关的是,当单击新选择以外的任何内容时,不会丢失SideButtons 中当前选择的突出显示。
    • 抱歉,还有一件事 - 我应该把 window eventListener 放在哪里才能与正在进行的 Game 兼容?我问的原因是完整的脚本使用requestAnimationFrameselectionMenu 或如您所说的sideButtons 上模拟带有滚动悬停事件的滚动。还有一种语言select 可以更改sideButtons 中文本的语言,在其当前状态下,还需要eventListener。如果这还不够,我可以更新关于 css select 的另一个问题,并举例说明我的意思,因为它是相关的。
    • 这取决于,我必须看到整个代码。 @乔纳森康奈尔
    【解决方案2】:

    问题是您的调整大小处理程序调用paintCanvas,并且在您的paintCanvas 方法中,您将全局paint 变量分配给paint 的全新实例。这完全消除了您的状态并强制重新绘制画布以匹配初始页面加载的初始状态。相反,您需要维护您的状态,清除您的画布并使用其现有状态再次渲染它,但只是使用新的尺寸。

    function paintCanvas() {
        c.width  = window.innerWidth;
        c.height = (2/3)*c.width;
        ctx=c.getContext('2d');
        rect = c.getBoundingClientRect();
    
        //paint = new Paint(c);
    

    注释掉//paint = new Paint(c); 会使您的状态保持不变。由于您不再破坏您的状态,因此您仍然需要清除并重新绘制一些残余物。

    var c=document.getElementById('game'),
        rect = c.getBoundingClientRect(),
    		ctx=c.getContext('2d');
    
    c.width  = window.innerWidth;
    c.height = (2/3)*c.width;
    
    numberImages = ['https://i.stack.imgur.com/TZIUz.png','https://i.stack.imgur.com/6beTF.png','https://i.stack.imgur.com/wZk2H.png','https://i.stack.imgur.com/1K743.png','https://i.stack.imgur.com/jMMmQ.png'];
    
    var curvedRect = function(number, x, y, w, h) {
        this.text = number.toString();
    	this.img = new Image();
    	this.img.src=numberImages[number-1];
    	this.x = x;
    	this.y = y;
    	this.w = w;
    	this.h = h;
    	this.hovered = false;
    	this.clicked = false;
    	this.visible = false;
    }
    
    var selected;
    curvedRect.prototype.makeCurvedRect = function() {
    	var delta=0, theta=0;
    	if (this.hovered) {
    		delta = (c.height*(3/500));
    		theta = -0.01;
    		shadowColor = '#000000';
    		shadowBlur = 20;
    		shadowOffsetX = 5;
    		shadowOffsetY = 5;
    	} else {
    		delta = 0;
    		theta = 0;
    		shadowColor = '#9F3A9B';
    		shadowBlur = 0;
    		shadowOffsetX = 0;
    		shadowOffsetY = 0;
    	}
    	var x = this.x-delta;
    	var y = this.y-delta;
    	var w = this.w+(2*delta);
    	var h = this.h+(2*delta);
    	var cornerRounder = (c.height*(10/500))
    	ctx.rotate(theta);
    	ctx.beginPath();
    	ctx.lineWidth='12';
    	ctx.strokeStyle='white';
    	ctx.moveTo(x+cornerRounder, y);
    	ctx.lineTo(x+w-cornerRounder, y);
    	ctx.quadraticCurveTo(x+w, y, x+w, y+cornerRounder);
    	ctx.lineTo(x+w, y+h-cornerRounder);
    	ctx.quadraticCurveTo(x+w, y+h, x+w-cornerRounder, y+h);
    	ctx.lineTo(x+cornerRounder, y+h);
    	ctx.quadraticCurveTo(x, y+h, x, y+h-cornerRounder);
    	ctx.lineTo(x, y+cornerRounder);
    	ctx.quadraticCurveTo(x, y, x+cornerRounder, y);
    	ctx.shadowColor = shadowColor;
    	ctx.shadowBlur = shadowBlur;
    	ctx.shadowOffsetX = shadowOffsetX;
    	ctx.shadowOffsetY = shadowOffsetY;
    	ctx.stroke();
    	ctx.shadowBlur = 0;
    	ctx.shadowOffsetX = 0;
    	ctx.shadowOffsetY = 0;
    	ctx.drawImage(this.img, x+(c.width*(2.5/750)), y+(c.height*(2.5/500)), w-cornerRounder/2, h-cornerRounder/2);
    	ctx.rotate(-theta);
    }
    
    curvedRect.prototype.hitTest = function(x, y) {
    	return (x >= this.x) && (x <= (this.w+this.x)) && (y >= this.y) && (y <= (this.h+this.y));
    }
    
    var selectionForMenu = function(id, text, y) {
    	this.id = id;
    	this.text = text;
    	this.y = y;
    	this.hovered = false;
    	this.clicked = false;
    	this.lastClicked = false;
    	this.visible = true;
    }
    
    function makeTextForSelected(text, y) {
    	ctx.font='bold '+(c.height*(12/500))+'px Noto Sans'; // check
    	ctx.fillStyle='white';
    	ctx.textAlign='center';
    	ctx.fillText(text, (c.width*(200/750)), y);
    }
    
    selectionForMenu.prototype.makeSelection = function() {
    	ctx.globalAlpha=0.75;
    	var fillColor='#A84FA5';
    	if (this.hovered) {
    		if (this.clicked) {
    			if (this.lastClicked) {
    				fillColor='#E4C7E2';
    				makeTextForSelected(this.text, c.height*(375/500));
    			} else {
    				fillColor='#D5A9D3';
    			}
    		} else if (this.lastClicked) {
    			fillColor='#D3A4D0';
    			makeTextForSelected(this.text, c.height*(375/500));
    		} else {
    			fillColor='#BA74B7';
    		}
    	} else if (this.lastClicked) {
    		fillColor='#C78DC5';
    		makeTextForSelected(this.text, c.height*(375/500));
    	} else {
    		fillColor='#A84FA5';
    	}
    	ctx.beginPath();
    	ctx.fillStyle=fillColor;
    	ctx.fillRect(c.width*(400/750), this.y, c.width*(350/750), c.height*(100/500))
    	ctx.stroke();
    
    	ctx.font=c.height*(10/500)+'px Noto Sans';
    	ctx.fillStyle='white';
    	ctx.textAlign='left';
    	ctx.fillText(this.text, c.width*(410/750), this.y+(c.height*(38/500)));
    
    	ctx.globalAlpha=1;
    }
    
    selectionForMenu.prototype.hitTest = function(x, y) {
    	return (x >= (c.width*(400/750)) && (x <= c.width) && (y >= this.y) &&
    	(y <= (this.y+(c.height*(100/500))) && !((x >= c.width*(400/750) && (y > c.height*(450/500))))));
    }
    
    var Paint = function(element) {
    	this.element = element;
    	this.shapes = [];
    }
    
    Paint.prototype.addShape = function(shape) {
    	this.shapes.push(shape);
    }
    
    Paint.prototype.render = function() {
    
    	ctx.clearRect(0, 0, this.element.width, this.element.height);
    
    	for (var i=0; i<this.shapes.length; i++) {
    		try {
    			this.shapes[i].makeSelection();
    		}
    		catch(err) {}
    		try {
    			if(this.shapes[i].lastClicked == true) {
    				this.shapes[i].rect.makeCurvedRect();
    			}
    		}
    		catch(err) {}
    	}
    
    	ctx.beginPath();
    	ctx.fillStyle='white';
    	ctx.fillRect(0, 0, c.width, (c.height*(25/500)));
    	ctx.stroke();
    
    	ctx.beginPath();
    	ctx.fillStyle='#BC77BA';
    	ctx.fillRect(0, (c.height*(450/500)), c.width, (c.height*(50/500)));
    	ctx.stroke();
    
    	ctx.font='bold '+(c.height*(10/500))+'px Noto Sans';
    	ctx.fillStyle='#9F3A9B';
    	ctx.textAlign='center';
    	ctx.fillText('Test', (c.width*(365/750)), (c.height*(17/500)));
    }
    
    Paint.prototype.setHovered = function(shape) {
    	for (var i=0; i<this.shapes.length; i++) {
    		this.shapes[i].hovered = this.shapes[i] == shape;
    	}
    	this.render();
    }
    
    Paint.prototype.setClicked = function(shape) {
    	for (var i=0; i<this.shapes.length; i++) {
    		this.shapes[i].clicked = this.shapes[i] == shape;
    	}
    	this.render();
    }
    
    Paint.prototype.setUnclicked = function(shape) {
    	for (var i=0; i<this.shapes.length; i++) {
    		if (shape.constructor.name==this.shapes[i].constructor.name) {
    			this.shapes[i].clicked = false;
    		 	if (shape instanceof selectionForMenu) {
    				this.shapes[i].lastClicked = this.shapes[i] == shape;
    				if (this.shapes[i].lastClicked == true) {
    					this.shapes[i].rect.visible = true;
    				} else {
    					this.shapes[i].rect.visible = false;
    				}
    			}
    		}
    	}
    	this.render();
    }
    
    Paint.prototype.select = function(x, y) {
    	for (var i=this.shapes.length-1; i >= 0; i--) {
    		if (this.shapes[i].visible == true && this.shapes[i].hitTest(x, y)) {
    			return this.shapes[i];
    		}
    	}
    	return null
    }
    
    var numbers = [1,2,3,4,5];
    var paint = new Paint(c);
    var selection = [];
    for (var i=0; i<numbers.length; i++) {
    	selection.push(new selectionForMenu(i+1, numbers[i], c.height*(25/500)+(c.height*((i*100)/500))));
    }
    for (var i=0; i<numbers.length; i++) {
    	var img = new curvedRect(i+1, (c.width*(112.5/750)), (c.height*(100/500)), (c.height*(175/500)), (c.height*(175/500)));
    	paint.addShape(img)
    	selection[i].rect = img;
    }
    
    for (var i=0; i<numbers.length; i++) {
    	paint.addShape(selection[i])
    }
    
    paint.render();
    
    var clickedShape, clickIndex=0;
    function mouseDown(event) {
    	var x = (event.pageX-rect.left)/(rect.right-rect.left)*c.width;
    	var y = (event.pageY-rect.top)/(rect.bottom-rect.top)*c.height;
    	var shape = paint.select(x, y);
    	if (shape instanceof selectionForMenu) {
    		if (clickIndex==0) {
    			clickedShape=shape;
    			clickIndex=1;
    		} else if (clickIndex==1) {
    			clickIndex=0;
    		}
    	}
    	paint.setClicked(shape);
    }
    
    function mouseUp(event) {
    	var x = (event.pageX-rect.left)/(rect.right-rect.left)*c.width;
    	var y = (event.pageY-rect.top)/(rect.bottom-rect.top)*c.height;
    	var shape = paint.select(x, y);
    	if (clickedShape instanceof selectionForMenu) {
    		if (x>c.width*(400/750) && y>c.height*(25/500) && y<c.height*(450/500)) {
    			paint.setUnclicked(shape);
    		} else if (shape && !(shape instanceof selectionForMenu)) {
    			paint.setUnclicked(shape);
    		}
    	}
    }
    
    function mouseMove(event) {
    	var x = (event.pageX-rect.left)/(rect.right-rect.left)*c.width;
    	var y = (event.pageY-rect.top)/(rect.bottom-rect.top)*c.height;
    	var shape = paint.select(x, y);
    
    	paint.setHovered(shape);
    }
    
    function paintCanvas() {
      c.width  = window.innerWidth;
      c.height = (2/3)*c.width;
      ctx=c.getContext('2d');
    
      rect = c.getBoundingClientRect();
     
      //paint = new Paint(c);
      selection = [];
      for (var i=0; i<numbers.length; i++) {
        selection.push(new selectionForMenu(i+1, numbers[i], c.height*(25/500)+(c.height*((i*100)/500))));
      }
      for (var i=0; i<numbers.length; i++) {
        var img = new curvedRect(i+1, (c.width*(112.5/750)), (c.height*(100/500)), (c.height*(175/500)), (c.height*(175/500)));
        paint.addShape(img)
        selection[i].rect = img;
      }
    
      for (var i=0; i<numbers.length; i++) {
        paint.addShape(selection[i])
      }
      paint.render();
    }
    
    paintCanvas();
    
    window.addEventListener('resize', paintCanvas);
    c.addEventListener('mousedown', mouseDown);
    c.addEventListener('mouseup', mouseUp);
    c.addEventListener('mousemove', mouseMove);
    canvas {
      z-index: -1;
      margin: 1em auto;
      border: 1px solid black;
      display: block;
      background: #9F3A9B;
    }
    <!doctype html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>uTalk Demo</title>
    	<link rel='stylesheet' type='text/css' href='wordpractice.css' media='screen'></style>
    </head>
    <body>
    	<div id='container'>
    		<canvas id="game"></canvas>
    	</div>
      <script type='text/javascript' src='scaleStack.js'></script>
    </body>
    </html>

    【讨论】:

    • 所以这似乎是朝着正确方向迈出的一步,但是如何在不重新定义图像并因此丢失选择的情况下缩放图像?另外,您知道我如何设置初始选择吗?
    • 更重要的是,即使在删除所有不是instance of curvedRectshapes 之后,当window 主要render 下有tracer 形状已调整大小。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多