我试图在HTML画布中编写一个滚动滚动功能,方法是定义一个hover
变量,检测指定悬停区域上的鼠标事件,并(在这样做时)添加或减去此悬停变量取决于悬停在哪个区域。此hover
变量连接到一系列选择按钮的位置,出于本示例的目的,这些按钮包含数字0到30.当这一系列选择按钮的任一端悬停在它们上方时,它们全部向上移动或者像滚动一样向下,但为了让它像滚动一样,你必须保持鼠标移动,因为每个新的rendered
事件画布只有mousemove
。
我的问题是如何在mouseover
上触发if (lowerHoverBoxHitTest(x, y))
或(upperHoverBoxHitTest(x, y))
上的事件(即如果鼠标悬停在下面脚本中定义的任一点击框中)悬停变量保持按设定增量(0.1
)添加,直到鼠标离开该区域。我尝试用if/else
循环替换function mouseMove
中的while
语句(因为它似乎在逻辑上类似于我所要求的),因此
while (lowerHoverBoxHitTest(x, y)) {
if (hover < 750) {
hover-=0.1;
}
}
while (upperHoverBoxHitTest(x, y)) {
if (hover > 0) {
hover+=0.1;
}
}
但这只会导致页面崩溃(可能是它会触发无限循环?)。除了this之外,关于此问题的Stack Overflow还没有多少,但是如果你的画布中还有很多其他东西你不想滚动,那么这个解决方案没用。(除非你是绝对定义我不想要的位置,这是我在完整项目中所做的。任何帮助将不胜感激。
var c=document.getElementById('game'),
canvasX=c.offsetLeft,
canvasY=c.offsetTop,
ctx=c.getContext('2d');
var hover=0;
function upperHoverBoxHitTest(x, y) {
return (x >= 0) && (x <= 350) && (y >= 0) && (y <= 50);
}
function lowerHoverBoxHitTest(x, y) {
return (x >= 0) && (x <= 350) && (y >= 450) && (y <= 500);
}
var selectionForMenu = function(id, text, y) {
this.id = id;
this.text = text;
this.y = y;
}
selectionForMenu.prototype.makeSelection = function() {
ctx.beginPath();
ctx.fillStyle='#A84FA5';
ctx.fillRect(0, this.y+hover, 350, 30)
ctx.stroke();
ctx.font='10px Noto Sans';
ctx.fillStyle='white';
ctx.textAlign='left';
ctx.fillText(this.text, 10, this.y+hover+19);
}
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++) {
this.shapes[i].makeSelection();
}
}
var paint = new Paint(c);
for (i=0; i<30; i++) {
paint.addShape(new selectionForMenu(i+1, i, i*30));
}
paint.render();
function mouseMove(event) {
var x = event.x - canvasX;
var y = event.y - canvasY;
paint.render();
if (lowerHoverBoxHitTest(x, y)) {
hover+=1;
} else if (upperHoverBoxHitTest(x, y)) {
hover-=1;
}
}
c.addEventListener('mousemove', mouseMove);
&#13;
canvas {
z-index: -1;
margin: 1em auto;
border: 1px solid black;
display: block;
background: #9F3A9B;
}
&#13;
<!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'>
</head>
<body>
<canvas id="game" width = "350" height = "500"></canvas>
</body>
</html>
&#13;
答案 0 :(得分:1)
如果符合条件,您需要有一个动画循环来增加/减少该值。如果你有一个循环(这比为每个动画对象添加动画循环更好)或者它自己的函数,这个循环可以是另一个循环。
动画循环执行所有渲染,并且仅在需要时(没有渲染已渲染的东西的点)。
Demo是OP代码的副本,修改后可以为滚动设置动画并为用户提供反馈。虽然不完整作为滚动选择框,但它需要一些调整才有用。
var c = document.getElementById('game'),
canvasX = c.offsetLeft,
canvasY = c.offsetTop,
ctx = c.getContext('2d');
var hover = 0;
const overTypes = {
lower : 1,
raise : 2,
none : 0,
}
var overBox = 0;
var overDist = 0;
const maxSpeed = 4;
const shapeSize = 30;
const hoverScrollSize = 50;
const gradUp = ctx.createLinearGradient(0, 0, 0, hoverScrollSize);
const gradDown = ctx.createLinearGradient(0, ctx.canvas.height - hoverScrollSize, 0, ctx.canvas.height);
gradUp.addColorStop(0, `rgba(${0xA8},${0x4F},${0xB5},1)`);
gradUp.addColorStop(1, `rgba(${0xA8},${0x4F},${0xB5},0)`);
gradDown.addColorStop(1, `rgba(${0xB8},${0x5F},${0xB5},1)`);
gradDown.addColorStop(0, `rgba(${0xB8},${0x5F},${0xB5},0)`);
c.addEventListener('mousemove', mouseMove)
c.addEventListener('mouseout', () => {
overBox = overTypes.none
}); // stop scroll when mouse out of canvas
// start the first frame
requestAnimationFrame(() => {
paint.render(); // paint first frame
requestAnimationFrame(mainLoop); // start main loop
});
function mainLoop() {
if (overBox !== overTypes.none) {
hover += overDist / hoverScrollSize * (overBox === overTypes.lower ? maxSpeed : -maxSpeed);
var bottom = - (paint.shapes.length - ctx.canvas.height / shapeSize) * shapeSize;
hover = hover > 0 ? 0 : hover < bottom ? bottom : hover;
paint.render();
}
requestAnimationFrame(mainLoop); // wait for next animation frame
}
function mouseMove(event) {
var x = event.clientX - canvasX;
var y = event.clientY - canvasY;
if (lowerHoverBoxHitTest(x, y)) {
overBox = overTypes.lower;
} else if (upperHoverBoxHitTest(x, y)) {
overBox = overTypes.raise;
} else {
overBox = overTypes.none;
}
}
function upperHoverBoxHitTest(x, y) {
overDist = hoverScrollSize - y;
return (x >= 0) && (x <= 350) && (y >= 0) && (y <= hoverScrollSize);
}
function lowerHoverBoxHitTest(x, y) {
overDist = y - (ctx.canvas.height - hoverScrollSize);
return (x >= 0) && (x <= 350) && (y >= ctx.canvas.height - hoverScrollSize) && (y <= ctx.canvas.height);
}
var selectionForMenu = function (id, text, y) {
this.id = id;
this.text = text;
this.y = y;
}
selectionForMenu.prototype.makeSelection = function () {
ctx.beginPath();
ctx.fillStyle = '#A84FA5';
ctx.fillRect(0, this.y + hover, 350, shapeSize)
ctx.stroke();
ctx.font = '10px Noto Sans';
ctx.fillStyle = 'white';
ctx.textAlign = 'left';
ctx.fillText(this.text, 10, this.y + hover + 19);
}
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++) {
this.shapes[i].makeSelection();
}
if (overBox !== overTypes.none) {
ctx.globalAlpha = 0.4 * (overDist / 50);
ctx.globalCompositeOperation = "lighter";
if (overBox === overTypes.raise) {
ctx.fillStyle = gradUp;
ctx.fillRect(0, 0, ctx.canvas.width, hoverScrollSize);
} else if (overBox === overTypes.lower) {
ctx.fillStyle = gradDown;
ctx.fillRect(0, ctx.canvas.height - hoverScrollSize, ctx.canvas.width, hoverScrollSize);
}
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1;
}
}
var paint = new Paint(c);
for (i = 0; i < 30; i++) {
paint.addShape(new selectionForMenu(i + 1, i, i * 30));
}
paint.render();
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'>
</head>
<body>
<canvas id="game" width = "350" height = "150"></canvas>
</body>
</html>