Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add onclick and onmouseover to canvas element

I want to add an onclick, onmouseover and an onmouseout events to individual shapes in a canvas element.

I have tried doing this with SVG in different ways and found no single method will work in all the major browsers.

Maybe, is there a simple way to add an onclick and probably other events to canvas shapes?

Can someone please show me how to add an onclick?

Here is my code:

canvas
{
  background:gainsboro;
  border:10px ridge green;
}
<canvas id="Canvas1"></canvas>
var c=document.getElementById("Canvas1");

var ctx=c.getContext("2d");
ctx.fillStyle="blue";
ctx.fillRect(10,10,60,60);

var ctx=c.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(80,60,60,60);

// these need an onclick to fire them up. How do I add the onclick
function blue()
{
  alert("hello from blue square")
}

function red()
{
  alert("hello from red square")
}
like image 887
Mr SVG Avatar asked May 18 '13 19:05

Mr SVG


People also ask

How to get a click event on a canvas element?

To get a click event on a canvas element (shape), you need to capture click events on the canvas HTML element and determine which element was clicked. This requires storing the element’s width and height. To add a click event to your canvas element, use the below-given code

What is onmouseover event in HTML?

The onmouseover event occurs when the mouse pointer is moved onto an element, or onto one of its children. Tip: This event is often used together with the onmouseout event, which occurs when a user moves the mouse pointer out of an element.

Where does onmouseover go after onclick attribute?

onmouseover="..."> You know how your code has all of the scripting inside of the onclick attribute? The onmouseover part goes after that onclick scripting code, before the end of the playButton2 button element. 1 Like next page → Home Categories

How to create an onClick event using CSS?

The most common way of creating a click event with CSS is using the checkbox hack. This method has broad browser support. You need to add a for attribute to the <label> element and an id attribute to the <input> element. Example of adding an onclick event by using the checkbox hack: ¶


1 Answers

Here is a barebones framework for adding events to individual canvas shapes

Here's a preview: http://jsfiddle.net/m1erickson/sAFku/

Unlike SVG, after you draw a shape to canvas, there is no way to identify that shape.

On canvas, there are no individual shapes, there is just a canvas full of pixels.

To be able to identity and “use” any individual canvas shape, you need to remember all basic properties of that shape.

Here are the properties necessary to identify a rectangle:

  • x-position,
  • y-position,
  • width,
  • height.

You will also want to remember some basic styling properties of a rectangle:

  • fillcolor,
  • strokecolor,
  • strokewidth.

So here is how to create a rectangle “class” object that remembers all of it’s own basic properties.

If you're not familiar with the term "class", think of it as a "cookie-cutter" that we can use to define a shape.

Then we can use the "cookie-cutter" class to create multiple copies of that shape.

Even better ... classes are flexible enough to let us modify the basic properties of each copy that we make.

For rectangles, we can use our one class to make many, many rectangles of different widths, heights, colors and locations.

The key here is that we create classes because classes are Very Flexible and Reusable!

Here is our rect class that "remembers" all the basic info about any custom rectangle.

// the rect class 

function rect(id,x,y,width,height,fill,stroke,strokewidth) {
    this.x=x;
    this.y=y;
    this.id=id;
    this.width=width;
    this.height=height;
    this.fill=fill||"gray";
    this.stroke=stroke||"skyblue";
    this.strokewidth=strokewidth||2;
}

We can reuse this class to create as many new rectangles as we need...And we can assign different properties to our new rectangles to meet our needs for variety.

When you create an actual rectangle (by filling in it's properties), every "cookie-cutter" copy of our class has its own private set of properties.

When we use a "cookie-cutter" class to create 1+ actual rectangles to draw on the canvas, the resulting real rectangles are called "objects".

Here we create 3 real rectangle objects from our 1 class. We have assigned each real object different width, height and colors.

var myRedRect = new rect("Red-Rectangle",15,35,65,60,"red","black",3);

var myGreenRect = new rect("Green-Rectangle",115,55,50,50,"green","black",3);

var myBlueRect = new rect("Blue-Rectangle",215,95,25,20,"blue","black",3);

Now let’s give our class the ability to draw itself on the canvas by adding a draw() function. This is where we put the canvas context drawing commands and styling commands.

rect.prototype.draw(){
    ctx.save();
    ctx.beginPath();
    ctx.fillStyle=this.fill;
    ctx.strokeStyle=this.stroke;
    ctx.lineWidth=this.strokewidth;
    ctx.rect(x,y,this.width,this.height);
    ctx.stroke();
    ctx.fill();
    ctx.restore();
}

Here’s how to use the draw() function to draw rectangles on the canvas. Notice that we have 2 rectangle objects and we must execute .draw() on both of them for 2 rects to show on the canvas.

var myRedRect = new rect("Red-Rectangle",15,35,65,60,"red","black",3);
myRedRect.draw();

var myBlueRect = new rect("Blue-Rectangle",125,85,100,100,"blue","orange",3);
myBlueRect.draw();

Now give the rect class the ability to let us know if a point (mouse) is inside that rect. When the user generates mouse events, we will use this isPointInside() function to test if the mouse is currently inside our rect.

// accept a point (mouseposition) and report if it’s inside the rect

rect.prototype.isPointInside = function(x,y){
    return( x>=this.x 
            && x<=this.x+this.width
            && y>=this.y
            && y<=this.y+this.height);
}

Finally we can tie our rect class into the normal browser mouse event system.

We ask jQuery to listen for mouse clicks on the canvas. Then we feed that mouse position to the rect object. We use the rect's isPointInside() to report back if the click was inside the rect.

// listen for click events and trigger handleMouseDown
$("#canvas").click(handleMouseDown);

// calc the mouseclick position and test if it's inside the rect
function handleMouseDown(e){

    // calculate the mouse click position
    mouseX=parseInt(e.clientX-offsetX);
    mouseY=parseInt(e.clientY-offsetY);

    // test myRedRect to see if the click was inside
    if(myRedRect.isPointInside(mouseX,mouseY)){

        // we (finally!) get to execute your code!
        alert("Hello from the "+myRedRect.id);
    }
}

// These are the canvas offsets used in handleMouseDown (or any mouseevent handler)
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;

Well...that's how you "remember" canvas shapes & how you execute the code in your question!

alert("hello from blue square")

That’s a barebones “class” that creates various rectangles and reports mouseclicks.

You can use this template as a starting point to listen for all mouse-events on all kinds of canvas shapes.

Almost all canvas shapes are either rectangular or circular.

Rectangular Canvas Elements

  • Rectangle
  • Image
  • Text
  • Line (yes!)

Circular Canvas Elements

  • Circle
  • Arc
  • Regular Polygon (yes!)

Irregular Canvas Elements

  • Curves (Cubic & Quad Beziers)
  • Path

The isPointInside() would look like this for a circle:

// check for point inside a circlular shape
circle.prototype.isPointInside = function(x,y){
    var dx = circleCenterX-x;
    var dy = circleCenterY-y;
    return( dx*dx+dy*dy <= circleRadius*circleRadius );
}

Even irregularly shaped canvas elements can have isPointInside, but that usually gets complicated!

That’s it!

Here is slightly enhanced code and a Fiddle: http://jsfiddle.net/m1erickson/sAFku/

<!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(){

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

    //
    var rect = (function () {

        // constructor
        function rect(id,x,y,width,height,fill,stroke,strokewidth) {
            this.x=x;
            this.y=y;
            this.id=id;
            this.width=width;
            this.height=height;
            this.fill=fill||"gray";
            this.stroke=stroke||"skyblue";
            this.strokewidth=strokewidth||2;
            this.redraw(this.x,this.y);
            return(this);
        }
        //
        rect.prototype.redraw = function(x,y){
            this.x=x;
            this.y=y;
            ctx.save();
            ctx.beginPath();
            ctx.fillStyle=this.fill;
            ctx.strokeStyle=this.stroke;
            ctx.lineWidth=this.strokewidth;
            ctx.rect(x,y,this.width,this.height);
            ctx.stroke();
            ctx.fill();
            ctx.restore();
            return(this);
        }
        //
        rect.prototype.isPointInside = function(x,y){
            return( x>=this.x 
                    && x<=this.x+this.width
                    && y>=this.y
                    && y<=this.y+this.height);
        }


        return rect;
    })();


    //
    function handleMouseDown(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // Put your mousedown stuff here
      var clicked="";
      for(var i=0;i<rects.length;i++){
          if(rects[i].isPointInside(mouseX,mouseY)){
              clicked+=rects[i].id+" "
          }
      }
      if(clicked.length>0){ alert("Clicked rectangles: "+clicked); }
    }


    //
    var rects=[];
    //
    rects.push(new rect("Red-Rectangle",15,35,65,60,"red","black",3));
    rects.push(new rect("Green-Rectangle",60,80,70,50,"green","black",6));
    rects.push(new rect("Blue-Rectangle",125,25,10,10,"blue","black",3));

    //
    $("#canvas").click(handleMouseDown);


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
like image 82
markE Avatar answered Sep 17 '22 01:09

markE