Recently I struggled to to the same with geo plots, which have a different coordinate system. I wrote the following function to cover all (?) possibilities and also to clip events that occur outside of the plotting area:
function eventToCursor(event) {
var layout = gd._fullLayout
x = event.offsetX - layout.margin.l
y = event.offsetY - layout.margin.t
if (x < 0 || y < 0 || x > layout.width || y > layout.height) {
return
}
if (layout.hasOwnProperty('xaxis')) {
x = layout.xaxis.p2c(x)
y = layout.yaxis.p2c(y)
cursor = {cursor: {x: x, y: y}}
} else {
if (layout.hasOwnProperty('geo')) {
geo = layout.geo
} else if (layout.hasOwnProperty('mapbox')) {
geo = layout.mapbox
} else {
return
}
x = geo._subplot.xaxis.p2c()
y = geo._subplot.yaxis.p2c()
cursor = {cursor: {lon: x, lat: y}}
}
return cursor
}