2012-09-09 13 views
5

Hay muchas respuestas, aquí en stackoverflow, sobre cómo obtener las coordenadas de un evento en un elemento Canvas, relativo al propio lienzo. Estoy usando la siguiente solución (getEventPosition) y funciona bien, excepto desde cuando agrego un borde a mi lienzo:Buscar coordenadas de un evento HTML5 Canvas (clic), con bordes

/**** This solution gives me an offset equal to the border size 
**** when the canvas has a border. Example: 
**** <canvas style='border: 10px solid black; background: #333;' id='gauge_canvas' width='500' height='500'></canvas> 
****/ 

// Get DOM element position on page 
this.getPosition = function(obj) { 
    var x = 0, y = 0; 
    if (obj.offsetParent) { 
     do { 
      x += obj.offsetLeft; 
      y += obj.offsetTop; 
      obj = obj.offsetParent; 
     } while (obj); 
    } 
    return {'x': x, 'y': y}; 
}; 

// Get mouse event position in DOM element (don't know how to use scale yet). 
this.getEventPosition = function(e, obj, aux_e, scale) { 

    var evt, docX, docY, pos; 

    evt = (e ? e : window.event); 
    if (evt.pageX || evt.pageY) { 
     docX = evt.pageX; 
     docY = evt.pageY; 
    } else if (evt.clientX || evt.clientY) { 
     docX = evt.clientX + document.body.scrollLeft + 
      document.documentElement.scrollLeft; 
     docY = evt.clientY + document.body.scrollTop + 
      document.documentElement.scrollTop; 
    } 
    // This works on hammer.js 
    else if (typeof aux_e !== 'undefined') { 
     docX = aux_e.touches[0].x; 
     docY = aux_e.touches[0].y; 
    } 
    pos = this.getPosition(obj); 
    if (typeof scale === 'undefined') { 
     scale = 1; 
    } 
    return {'x': (docX - pos.x)/scale, 'y': (docY - pos.y)/scale}; 
}; 

Desde este código pertenece a mi biblioteca y puede tomar cualquier elemento canvas un usuario se lo da, cuando un usuario le da a la biblioteca un lienzo con borde, las cosas se rompen. ¿Hay una solución que tenga fronteras en cuenta?

Respuesta

3

Aquí es lo que he estado usando durante mi último experimentación.

http://jsfiddle.net/simonsarris/te8GQ/5/

var stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingLeft'], 10) || 0; 
var stylePaddingTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingTop'], 10) || 0; 
var styleBorderLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderLeftWidth'], 10) || 0; 
var styleBorderTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderTopWidth'], 10) || 0; 
var html = document.body.parentNode; 
var htmlTop = html.offsetTop; 
var htmlLeft = html.offsetLeft; 

function getMouse(e) { 
    var element = can, 
     offsetX = 0, 
     offsetY = 0, 
     mx, my; 

    // Compute the total offset 
    if (element.offsetParent !== undefined) { 
     do { 
      offsetX += element.offsetLeft; 
      offsetY += element.offsetTop; 
     } while ((element = element.offsetParent)); 
    } 

    // Add padding and border style widths to offset 
    // Also add the <html> offsets in case there's a position:fixed bar 
    offsetX += stylePaddingLeft + styleBorderLeft + htmlLeft; 
    offsetY += stylePaddingTop + styleBorderTop + htmlTop; 

    mx = e.pageX - offsetX; 
    my = e.pageY - offsetY; 

    // We return a simple javascript object (a hash) with x and y defined 
    return { 
     x: mx, 
     y: my 
    }; 
} 

Funciona con cualquier frontera y el relleno y también trabaja en las páginas que cuña en un objeto que compensa el HTML (como la barra StumbleUpon). También funciona si se amplía el navegador.

Parece que funciona bien en dispositivos táctiles también.

0

Prueba esto:

this.getPosition = function(obj) { 
    var x = 0, y = 0; 
    if (obj.offsetParent) { 
     do { 
      x += obj.clientLeft; 
      y += obj.clientTop; 
      obj = obj.offsetParent; 
     } while (obj); 
    } 
    return {'x': x, 'y': y}; 
}; 

clientLeft y clientTop incluyen las fronteras, pero offsetLeft y offsetTop no.

Si no desea incluir otros elementos, tal vez el siguiente trabajo:

this.getPosition = function(obj) { 
    return{'x': obj.clientLeft, 
      'y': obj.clientTop}; 
}; 
+1

Esto no solo no resuelve el problema, sino que agrega la altura de los dos elementos h1 en la parte superior del lienzo a la coordenada y que devuelve :( – janesconference

+0

@janesconference He editado mi respuesta, pruébelo. Puede proporcionar un jsfiddle con todo su código para probarlo. – Oriol

+1

La solución editada sigue incluyendo otros elementos. – janesconference