Skip to content Skip to sidebar Skip to footer

HTML Canvas & Javascript - Emulating A Scroll-On-Hover Event

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 su

Solution 1:

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>

Post a Comment for "HTML Canvas & Javascript - Emulating A Scroll-On-Hover Event"