HTML画布& Javascript - 模拟一个滚动上移动事件 [英] HTML Canvas & Javascript - Emulating a Scroll-On-Hover Event

查看:99
本文介绍了HTML画布& Javascript - 模拟一个滚动上移动事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过定义一个 hover 变量在HTML画布中编写一个滚动悬停函数,在指定的悬停区域上检测鼠标事件(在做所以)添加或减去这个悬停变量取决于哪个区域被悬停。这个 hover 变量连接到一系列选择按钮的位置,为了这个例子的目的,它包含数字0到30.当这一系列的任一端选择按钮被悬停在它们上方,就像滚动一样向上或向下移动,但是为了使其像滚动一样,您必须保持鼠标移动,因为画布仅在渲染新的 mousemove 事件。



我的问题是如何在 mouseover 上触发事件,使 if(lowerHoverBoxHitTest (x,y))(upperHoverBoxHitTest(x,y))(即,如果鼠标悬停在任何一个定义的命中框中下面的脚本),通过设置的增量( 0.1 )将悬停变量保持添加到鼠标离开该区域。我已经尝试将 if / else 语句替换为函数mouseMove 循环(因为它似乎在逻辑上类似于我所要求的),所以

  while(lowerHoverBoxHitTest (x,y)){
if(hover< 750){
hover- = 0.1;
}
}

while(upperHoverBoxHitTest(x,y)){
if(hover> 0){
hover + = 0.1;
}
}

但这只会导致页面崩溃(大概是触发无限循环?)。除了之外,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 =白色; ctx.textAlign =左; 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();函数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);  

  canvas {z-index:-1;保证金:1em自动;边框:1px纯黑色;显示:块;背景:#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 =gamewidth =350height =500>< / canvas>< / body>< / html>  

/ div>

解决方案

动画通过动画循环



如果满足条件,则需要有一个动画循环来增加/减小该值。如果你有一个循环(这比为每个动画对象添加一个动画循环)还是自己的函数,这个循环可以是另一个循环的一部分。



动画循环所有的渲染,只有在需要时(没有点渲染已经呈现的东西)。



演示



演示是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.addEven tListener('mousemove',mouseMove)c.addEventListener('mouseout',()=> {overBox = overTypes.none}); //停止滚动鼠标从画布//启动第一个framerequestAnimationFrame(()=> {paint.render(); //绘制第一帧requestAnimationFrame(mainLoop); //启动主循环});函数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:悬停底部?底部:悬停; paint.render(); } requestAnimationFrame(mainLoop); //等待下一个动画框架} 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)& amp;& (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 =更轻; 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;保证金:1em自动;边框:1px纯黑色;显示:块;背景:#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 =gamewidth =350height =150>< / canvas>< / body>< / html>  

/ div>


I am trying to write a scroll-on-hover function in an HTML canvas by defining a hover variable, detecting mouse events over the designated hover area and (on doing so) adding or subtracting to this hover variable depending on which area is hovered over. This hover variable is connected to the position of a series of selection buttons which, for the purposes of this example, contain the numbers 0 to 30. When either end of this series of selection buttons is hovered over they all move up or down as if scrolled, but to make it act like a scroll you must keep the mouse moving as the canvas is only rendered on each new mousemove event.

My question is how can I trigger the event on mouseover such that if (lowerHoverBoxHitTest(x, y)) or (upperHoverBoxHitTest(x, y)) (i.e if the mouse is hovered over either of the hit boxes defined in the script below) the hover variable keeps being added to by the set increment (0.1) until the mouse leaves that area. I have tried replacing the if/else statement in the function mouseMove with a while loop (as it would seem this is logically akin to what I am asking) as so

while (lowerHoverBoxHitTest(x, y)) {
    if (hover < 750) {
      hover-=0.1;
    }
} 

while (upperHoverBoxHitTest(x, y)) {
    if (hover > 0) {
      hover+=0.1;
    }
}

but this just causes the page to crash (presumably it triggers an infinite loop?). There isn't much on Stack Overflow about this besides this but this solution is not useful if you have a lot of other things in your canvas that you don't want to scroll (unless you were to define their position absolutely which I don't want to) which I do in my full project. Any help will be appreciated.

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);

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 = "500"></canvas>
</body>
</html>

解决方案

Animation via animation loops.

You need to have an animation loop that will increment/decrement the value if the conditions are met. This loop can be part of another if you have one (which is better than adding an animation loop for each animated object) or as its own function.

The animation loop does all the rendering, and only if needed (no point rendering something that is already rendered).

Demo

Demo is a copy of the OP's code with modifications to animate the scrolling and give a little user feed back. Though not complete as a scrolling selection box, it will need some tweaking to be useful.

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>

这篇关于HTML画布&amp; Javascript - 模拟一个滚动上移动事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆