Suffii
Suffii

Reputation: 5784

Issue Adding Mouse Hover Animation to HTML5 Canvas Drawings

Could you please take a look at this demo and let me know how to add CSS animation to the drawing via CSS3 or jQuery? I want to make the circle bigger or change its background color on mouseover.

<canvas id="myCanvas" width="200" height="100" style="border:1px solid #d3d3d3;">Your browser does not support the HTML5 canvas tag.</canvas>


var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(95, 50, 20, 0, 2 * Math.PI);
ctx.fillStyle = "#FF8C00";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = '#2d2d2d';
ctx.stroke();

This is what I tried:

ctx.hover(
    function() {
        ctx.animate({
            fillStyle: 'yellow'
        }, 300);
    },
    function() {
        ctx.animate({
            fillStyle: 'red'
        }, 300);
    }
);

But it didn't work! Thanks.

Upvotes: 3

Views: 3402

Answers (1)

markE
markE

Reputation: 105035

You can't control html canvas drawings with either CSS or jQuery.

DOM elements can trigger events on hover because they are objects and the browser knows their position and is tracking the mouse for you.

Unlike DOM elements, canvas drawings are just pixels on the canvas--not objects. After they are drawn, the browser does not track the pixels and the pixels cannot trigger any events.

What is typically done is to "simulate" hover behavior in canvas drawings using javascript.

  • Listen for mousemove events on the canvas.

  • In the mousemove handler, calculate if the mouse is inside the circle.

  • If the mouse has changed from outside-circle to inside-circle then simulate a hover.

  • If the mouse has changed from inside-circle to outside-circle then simulate a blur.

Since canvas drawings are just pixels, to change the way a drawing looks you must actually erase the pixels and redraw it with your desired effect. So in your case:

On simulated hover:

  • erase the canvas

  • redraw the circle larger or with recolored fill

On simulated blur:

  • erase the canvas

  • redraw the circle with its original size and fill

And if you want to animate a drawing on html canvas, you must also do that manually with javascript:

  1. Change the circles properties incrementally (slightly increased size or slightly changed color);

  2. Erase the canvas.

  3. Draw the circle in its new incrementally changed state.

  4. Repeat at #1 until the animation is complete.

Hint: using requestAnimationFrame is gives high performance to your animations. R.A.F. lets you create animation loops that are coordinated with browser refreshes to give good performance.

Example code and a Demo: http://jsfiddle.net/m1erickson/h3Hc7/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    // canvas related variables

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var scrollX=$canvas.scrollLeft();
    var scrollY=$canvas.scrollTop();

    // create an object that represents the circle

    var circle={
        cx:95,
        cy:50,
        radius:20,
        blurColor:"#FF8C00",
        hoverColor:"red",
        wasInside:false,
    }

    // draw the circle on the canvas the first time

    drawCircle(circle,false);


    // draw a circle on the canvas in a color that represents its hover state

    function drawCircle(circle,isInside){
        ctx.beginPath();
        ctx.arc(circle.cx,circle.cy,circle.radius, 0, 2 * Math.PI);
        ctx.fillStyle = isInside ? circle.hoverColor : circle.blurColor;
        ctx.fill();
        ctx.lineWidth = 4;
        ctx.strokeStyle = '#2d2d2d';
        ctx.stroke();
        // save the hover status of this circle
        circle.wasInside=isInside;
    }


    function handleMouseMove(e){

      // tell the browser that we're handling this event

      e.preventDefault();
      e.stopPropagation();

      // calculate the mouse position

      var mouseX=parseInt(e.clientX-offsetX);
      var mouseY=parseInt(e.clientY-offsetY);

      // calculate if the mouse is currently inside the circle

      var dx=mouseX-circle.cx;
      var dy=mouseY-circle.cy;
      var isInside=dx*dx+dy*dy<=circle.radius*circle.radius;

      // if the mouse has either entered or exited the circle
      // then erase and redraw the circle to reflect its current 
      // hover state

      if( isInside && !circle.wasInside ){
          ctx.clearRect(0,0,canvas.width,canvas.height);
          drawCircle(circle,isInside);
      }else if( !isInside && circle.wasInside ){
          ctx.clearRect(0,0,canvas.width,canvas.height);
          drawCircle(circle,isInside);
      }

    }

    // listen for mousemove events

    $("#canvas").mousemove(function(e){handleMouseMove(e);});

}); // end $(function(){});
</script>
</head>
<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Upvotes: 4

Related Questions