1
\$\begingroup\$

I need to draw some 2D objects on a canvas. And I need to map the 2D coordinates of clicks to objects.

What is the usual way to maintain a 2D object's size and position (which data structures, etc.)? What's the effective way to say: this object is at coordinates (x, y)?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Iterating through an array of objects checking for their intersection with a given point would be an effective method. But a more efficient method would be using a spatial subdivision data structure like a Quadtree.

\$\endgroup\$
2
  • \$\begingroup\$ Thnx, Quadtree is, what i was looking for! \$\endgroup\$
    – Skip
    Nov 28, 2012 at 8:37
  • \$\begingroup\$ It's true. Still, it depends on the item count. There is quite a cost for a QuadTree, so maybe if there are less than 20 items an array is better, and if you have more than 50 items you can be sure a Quadtree will be way better. \$\endgroup\$ Nov 28, 2012 at 10:30
2
\$\begingroup\$

I don't know if you are using a Game Framework, so i will give you here a few hints using 'standard' javascript. You might have to adapt them to your Framework.

So let us say we have a 'namespace' gg:

 var gg={};

We create an array containing all our graphic objects :

 var gg.GraphicObjects = [];

We add a method to add a graphic object :

 var gg.addGraphicObject = function (x, y, width, height, parameters)
  {
     var newGraphicObject = { x:x, y:y, width: width, height : height, 
              id : parameters.id, clickCallback : parameters.clickCallback , 
              hoveringCallback : parameters.hoveringCallback };
     gg.GraphicObjects.push( newGraphicObject );
     return newGraphicObject;
  }

parameters containing : id : string identifying the object, hoveringCallback : ..., clickCallback : ... , and you might think of other properties.

Rq that you must bind the callbacks if you reference to 'this' in the callbacks :

 var myObjectHandle = gg.addGraphicObject(100,100,60,60, { id : 'start',
                                    clickCallBack: this.start.bind(this) });

then you must handle click, which is done like this in a standard way (again, your framework might handle it allready) :

// myCanvas is the main page canvas ( = document.getElementById('myCanvasName'); )
myCanvas.addEventListener('click', on_click, false);
var  on_click = function(ev) {
    var mx = ev.clientX ;  //- CanvasLeftOffset ; if you use offsets (offsetLeft)
    var my = ev.clientY ; // - CanvasTopOffset ;  if you use offsets  (offsetTop)
    for (var i=0; i <gg.GraphicObjects.lenght ; i++) {
       var gObj=gg.GraphicObjects[i];
       if (gg._inRect(mx, my, gObj) ) 
          {
            if (gObj.clickCallBack) { gObj.clickCallBack(); }
          }
     }
 } 

 gg._inRect : function(x, y, gObj ) {
         return   x >= gObj.x               &&
                  x <  gObj.x + gObj.width   &&
                  y >= gObj.y               &&
                  y <  gObj.y + gObj.height;
    }

if you want to handle mouseOver, it's a little bit trickyer (?), since the mousemove event is just triggering too often and is annoying... but you can cool it down using a setTimeout in this way :

gg.mouseMoveRefresh = 30; // number of mouse move refresh per second

gg._onmousemove =   function() {
   for (var i=0; i <gg.GraphicObjects.lenght ; i++) {
       var gObj=gg.GraphicObjects[i];
       if (gg._inRect(mx, my, gObj) ) 
          {  
            gObj.isMouseOver = true;
            if (gObj.hoveringCallback ) { gObj.hoveringCallback (); }
          }
        else gObj.isMouseOver = false; 
     }
    myCanvas.onmousemove= null;
    setTimeout( gg.onMouseMoveSet, 1000 / gg.mouseMoveRefresh);
     }

gg.onMouseMoveSet =  function() {
    myCanvas.onmousemove = gg._onmousemove; 
  }

gg.onMouseMoveSet();

Notice that if you resize your canvas you might have to set again event listeners (i couldn't get a clear opinion about this behaviour cross-browsers/OS/versions/etc...).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .