HTML Canvas & JavaScript - 重新定义选择对象



下面的脚本在屏幕左侧绘制一个图像,在右侧绘制一个选择框。然后,它尝试通过使imageID依赖于选择来重新定义右侧选择框中每个新选择的左侧绘制的图像。然而,正如你在下面看到的,无论你在右边选择什么数字,图像都保持不变(1),因为虽然它可能会被重新绘制,但它不会在选择时重新定义。我想发生的是,在右侧框中的选择中,图像中的数字会随着选择框的变化而变化,以便它始终与选择相关。换句话说,当您单击 2 时,图像将更改为images中的第 2 张图像。我找到了两种方法,但它们都有缺陷:

1:paintrender函数中定义img。这有效,但它使一切运行非常缓慢,并且图像上的悬停动画停止按预期工作。

2:makeSelectionInfo函数中定义img。这也有效,但如果这样做,悬停动画将完全停止工作。

对于长代码,我深表歉意,但我无法再压缩它了。为了简洁起见,我只包含 1 到 5 之间的数字图像。任何帮助将不胜感激。

var c=document.getElementById('game'),
		canvasX=c.offsetLeft,
		canvasY=c.offsetTop,
		ctx=c.getContext('2d');
images=['https://i.stack.imgur.com/KfN4z.jpg',
'https://i.stack.imgur.com/MyQS1.png',
'https://i.stack.imgur.com/3Vlfj.jpg',
'https://i.stack.imgur.com/u3NLH.jpg',
'https://i.stack.imgur.com/XnLwl.png'];
var curvedRect = function(text, x, y, w, h) {
this.text = text;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.hovered = false;
this.clicked = false;
}
curvedRect.prototype.makeCurvedRect = function() {
var delta=0, theta=0, yRotation=this.y;
if (this.hovered) {
	delta = 3;
	shadowColor = '#000000';
	shadowBlur = 20;
	shadowOffsetX = 5;
	shadowOffsetY = 5;
	theta = -0.01;
} else {
	delta = 0;
	theta = 0;
	shadowColor = '#9F3A9B';
	shadowBlur = 0;
	shadowOffsetX = 0;
	shadowOffsetY = 0;
}
var x = this.x-delta;
var y = yRotation-delta;
var w = this.w+(2*delta);
var h = this.h+(2*delta);
var img=new Image();
img.src=images[this.text];
ctx.rotate(theta);
ctx.beginPath();
ctx.lineWidth='8';
ctx.strokeStyle='white';
ctx.moveTo(x+10, y);
ctx.lineTo(x+w-10, y);
ctx.quadraticCurveTo(x+w, y, x+w, y+10);
ctx.lineTo(x+w, y+h-10);
ctx.quadraticCurveTo(x+w, y+h, x+w-10, y+h);
ctx.lineTo(x+10, y+h);
ctx.quadraticCurveTo(x, y+h, x, y+h-10);
ctx.lineTo(x, y+10);
ctx.quadraticCurveTo(x, y, x+10, 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(img, x+2.5, y+2.5, w-5, h-5);
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;
}
function makeTextForSelected(text, y) {
ctx.font='bold 12px Noto Sans';
ctx.fillStyle='white';
ctx.textAlign='center';
ctx.fillText(text, 200, y);
}
function makeSelectionInfo(text) {
makeTextForSelected(text, 375);
}
selectionForMenu.prototype.makeSelection = function() {
	var fillColor='#A84FA5';
	if (this.hovered) {
		if (this.clicked) {
			if (this.lastClicked) {
				fillColor='#E4C7E2';
			} else {
				fillColor='#D5A9D3';
			}
		} else if (this.lastClicked) {
			fillColor='#D3A4D0';
			makeSelectionInfo(this.text);
		} else {
			fillColor='#BA74B7';
		}
	} else if (this.lastClicked) {
		fillColor='#C78DC5';
		makeSelectionInfo(this.text);
	} else {
		fillColor='#A84FA5';
	}
	ctx.beginPath();
	ctx.fillStyle=fillColor;
	ctx.fillRect(400, this.y, 350, 30)
	ctx.stroke();
	ctx.font='10px Noto Sans';
	ctx.fillStyle='white';
	ctx.textAlign='left';
	ctx.fillText(this.text, 410, this.y+19);
}
selectionForMenu.prototype.hitTest = function(x, y) {
	return (x >= 400) && (x <= (750)) && (y >= this.y) && (y <= (this.y+30)) && !((x >= 400) && (y > 450));
}
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 {
			this.shapes[i].makeCurvedRect();
		}
		catch(err) {}
	}
	ctx.beginPath();
	ctx.fillStyle='white';
	ctx.fillRect(0, 0, 750, 25);
	ctx.stroke();
	for (var i=0; i<this.shapes.length; i++) {
		try {
			this.shapes[i].makeBox();
		}
		catch(err) {}
	}
	ctx.beginPath();
	ctx.fillStyle='#BC77BA';
	ctx.fillRect(0, 450, 750, 50);
	ctx.stroke();
	ctx.font='bold 10px Noto Sans';
	ctx.fillStyle='#9F3A9B';
	ctx.textAlign='center';
	ctx.fillText('Phrase Practice', 365, 17);
	for (var i=0; i<this.shapes.length; i++) {
		try {
			this.shapes[i].makeInteractiveButton();
		}
		catch(err) {}
	}
}
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;
			}
		}
	}
	this.render();
}
Paint.prototype.select = function(x, y) {
	for (var i=this.shapes.length-1; i >= 0; i--) {
		if (this.shapes[i].hitTest(x, y)) {
			return this.shapes[i];
		}
	}
	return null
}
imageID = 0;
var paint = new Paint(c);
var img = new curvedRect(imageID, 112.5, 100, 175, 175);
var selection = [];
for (i=0; i<=30; i++) {
	selection.push(new selectionForMenu(i, i, 25+(i*30)));
}
paint.addShape(img);
for (i=0; i<30; i++) {
	paint.addShape(selection[i])
}
paint.render();
var clickedShape=0;
var i=0;
function mouseDown(event) {
	var x = event.x - canvasX;
	var y = event.y - canvasY;
	var shape = paint.select(x, y);
	if (shape instanceof selectionForMenu) {
		imageTextID = shape.id;
		if (i==0) {
			clickedShape=shape;
			i=1;
		} else if (i==1) {
			i=0;
		}
	}
	paint.setClicked(shape);
}
function mouseUp(event) {
	var x = event.x - canvasX;
	var y = event.y - canvasY;
	var shape = paint.select(x, y);
	if (clickedShape instanceof selectionForMenu) {
		if (x>400 && y>25 && y<450) {
			paint.setUnclicked(shape);
		} else if (shape && !(shape instanceof selectionForMenu)) {
			paint.setUnclicked(shape);
		}
	}
}
function mouseMove(event) {
	var x = event.x - canvasX;
	var y = event.y - canvasY;
	var shape = paint.select(x, y);
	paint.setHovered(shape);
}
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>
</head>
<body>
	<canvas id="game" width = "750" height = "500"></canvas>
</body>
</html>

在这里修复了你的代码 https://jsfiddle.net/0wq0hked/2/

您可以比较以查看我更改的内容,但基本上您没有初始化并将多个curvedRect添加到Paint.shapes数组中。我还添加了图像作为curvedRect的属性。

我还必须为您的形状添加一个visible参数,因为您的鼠标悬停Paint.select功能无法正常运行。按照您的工作方式,共享相同 (x,y) 的形状不允许将鼠标悬停在其他形状上,即使它们不可见也是如此。因此,占据左侧图像区域的多个形状阻止了悬停正常工作。我想您可以在绘制形状时保留Paint.select并实例/删除形状,但据我所知,您没有形状删除功能。

此外,您在每个事件上调用渲染,这是一个坏主意。查看requestAnimationFrame并尝试以屏幕刷新率而不是用户输入进行绘制。

最新更新