On 03/12/2011 00:38, David Mark wrote:
On Nov 11, 4:33 pm, Dr J R Stockton<
[email protected]>
wrote:
OneTipmight be the answer to "I have an on-screen element, of known
size, with an on[dbl]click method; how do I obtain the co-ordinates of a
[double-]click with respect to a given position in the element itself?"
Tricky.
Your best bet is to see thetipof the day related to coordinates.
From that you should be able to get the coordinates of the element
relative to the viewport (or "window" as I think I referred to it in
that post). So you will need the mouse coordinates relative to the
viewport. Ironically enough, it's trivial to find those in the oldIE
versions that lacked pageX/Y properties. But for everything else, you
have to have to subtract the scroll position as pageX/Y are relative
to the document. Depending on context, getting the scroll positionis
either trivial (one-liner) or fairly complex. Frustratingly, it's IE
(all versions AFAIK) that needs most of the extra code in this case.
You also have to consider other factors like whether you will need
this to work in quirks mode (hopefully not)
It looks like:-
// No quirks mode, frames or other windows (just the one running the
script)
var getScrollPosition;
if ('number' == typeof window.pageXOffset) {
// Many "standards-based" browsers feature this non-standard
property
// No ambiguity about what this window property means
window.pageYOffset is available as of IE9, FF3+, Safari 4+, Chrome 4+,
Opera 10+.
IE 8 and older browsers in standards-compliant mode (strict mode) woulduse:
if (document.documentElement && document.documentElement.scrollTop) {
return document.documentElement.scrollTop;
But IE in quirks mode (tested with IE8) would use:
if (document.body) {
return document.body.scrollTop;
So let's finish this off. If you need it to work in IE 9 and
virtually every other browser made since the turn of the century:-
if ('number' == typeof window.pageXOffset) {
getScrollPosition = function() {
return [window.pageXOffset, window.pageYOffset];
};
// I suppose jQuery users would prefer gPtrPosRel2Win or some such
"concise" BS.
// Works for mouse or touch
getPointerPositionRelativeToViewport = function(e) {
return [e.pageX - window.pageXOffset, e.pageY -
window.pageYOffset]
};
}
Piece of cake (as this context usually is).
Now, what if you need IE 6-8 to join in the fun?
Put this script inside conditional comments (so the others don't
download it):-
// Last test is to exclude IE quirks mode and IE 5
if (document.documentElement && 'number' == typeof
document.documentElement.scrollLeft &&
document.documentElement.clientWidth) {
getScrollPosition = function() {
// Note: optimize by saving a reference to documentElement (saves
two dot operations)
return [document.documentElement.scrollLeft,
document.documentElement.scrollTop];
};
getPointerPositionRelativeToViewport = function(e) {
// Yes, we would use these in non-IE browsers too if history of
implementation
// wasn't atrocious. Perhaps in a few years...
// Regardless, you know for sure these work as advertised in
legacy IE versions
// NOTE: the HTML border "issue" is irrelevant as same offset for
element positions
return [e.clientX, e.clientY]
};
}
// Detect API features (never changes, regardless of specific
renditions used)
// Self-documenting (really, not like jQuery's claims)
if (getScrollPosition && getPointerPositionRelativeToViewport) {
var el = getElementById('johnstockton');
el.onmousedown = ...
el.ondblclick = ...
}
Will leave rest as an exercise.
A solution. This is the "good riddance to bad baggage" environment
context.
// This function fades away in IE 8- and compatibility modes
if ('number' == typeof window.pageXOffset) {
// Works for mouse or touch
getPointerPositionRelativeToViewport = function(e) {
return [e.pageX - window.pageXOffset, e.pageY -
window.pageYOffset]
};
}
/*
* Need these two API functions
* See position tip for first function
* Should need the normalized rendition that subtracts
documentElement.clientLeft/Top
* as comparing element position to pointer position results that
don't have the
* client-related quirk (i.e. getBoundingClientRect, clientX/Y not
involved)
* Quirk must be present or absent on both sides of the equation to be
factored out.
*/
if (getElementPositionRelativeToViewport &&
getPointerPositionRelativeToViewport) {
var el = getElementById('johnstockton');
var pointerPosition;
// NOTE: should only respond to one event type at a time
el.onmousedown = el.ontouchstart = function(e) {
pointerPosition = getPointerPositionRelativeToViewport(e);
};
el.onclick = function(e) {
/*
* Make sure a mousedown/touchstart preceded the click on this
element
* If another mousedown listener hid an element that was covering
* the "johnstockton" element, could get click without mousedown
*/
if (pointerPosition) {
var elementPosition =
getElementPositionRelativeToViewport(this);
window.alert([pointerPosition[0] - elementPosition[0],
pointerPosition[1] - elementPosition[1]]);
// One click per mousedown/touchstart
pointerPosition = null;
}
};
}
If wrapped in a function, be sure to set el to null (to break circular
references). As usual, no warranty, may not be appropriate for your
needs, etc.
As mentioned, you can add this to create a legacy IE rendition,
perhaps even putting it inside conditional comments, loading it only
for version 8 and under (which will also catch compatibility mode).
if (document.documentElement && 'number' == typeof
document.documentElement.scrollLeft && 'number' == typeof
document.documentElement.clientLeft &&
document.documentElement.clientWidth) {
getPointerPositionRelativeToViewport = function(e) {
return [e.clientX - document.documentElement.clientLeft,
e.clientY - document.documentElement.clientTop]
};
}
Note that this is also a normalized rendition as the results will be
compared to the results of the normalized element position function
that accounts for IE's chrome HTML border. Quirk is absent on both
sides of the equation.
It should be mentioned that it is best not to put borders on the HTML
element, otherwise ambiguity is introduced in the relationship between
clientLeft/Top values (normally 0) and element coordinates. Certainly
HTML borders are not part of the Chrome in other browsers that copied
getBoundingClientRect, so it is unrealistic to assume they treated the
HTML borders the same. Last I heard somebody was trying to stamp a
standard on this mess (and good luck to them), but that will only make
a difference on paper.
IIRC, all works out even with HTML borders in other browsers, but why
tempt fate? Probably doesn't need mentioning that putting borders on
the HTML element is crazy anyway. This is the sort of non-issue that
public libraries love to tackle.
I spent hours putting margins and borders on the HTML (body in quirks
mode) element when testing My Library. I suppose I could justify the
waste of time as an academic exercise, but wouldn't recommend using
the results over functions like the above. As soon as you lose sight
of your context, extraneous complications start to appear. This
happens automatically in projects that involve collaboration with lots
of other developers, each likely thinking in the context of their
current (downstream) efforts.
Doesn't take long before the best hint you can give about the
functions is that they pass some tests in some recent versions of
Chrome, Safari, Opera, Firefox and some versions/modes of IE. Other
browsers, which is the what today's browsers will be tomorrow, are
anyone's guess. The oft-heard line: "we don't care about [browser x]"
is truly indicative of a careless, cavalier and ultimately futile
approach to browser scripting.
Unless you want to be on an endless treadmill, "keeping up" with five
(then seven, then nine...) browsers, you want cross-browser code,
which tests features and does *nothing* in environments that fail.
Therefore, during development and testing, it is necessary to load a
script in at least *one* browser that is not expected to pass the
tests (usually an old browser). The jQuery way of wearing blinders
and quoting recent browser version numbers as the starting point of
their caring is a perfectly ridiculous strategy, particularly as rapid
change in browser differences (which jQuery ostensibly buffers) is
what neophytes fear the most. If the library developers are that
focused on Chrome 4+, Opera 10+, etc., you have to wonder how they
managed to screw up Opera 9- or Chrome 3-; probably because they were
so focused on Opera 9+ and Chrome 3+ at the time. This sort of
nonsense has been going on since the late 90's. Just steer clear of
projects with five browser icons lined up to indicate their perceived
"compatibility". Think Dynamic Drive with three more icons.
Nothing is guaranteed, but cross-browser code has the best shot at
lasting from one cycle of browser "innovation" to the next and to fade
away gracefully as today's browsers go the way of Netscape 6.
When you consider mobile users, most are using "other browsers"
today. The browser in Android devices is not Chrome. iOS devices do
not run the same Safari as found on desktops. Then there are the
mobile versions of Opera and Firefox and the new Windows phones, which
are clearly not exactly the same as their desktop counterparts. And,
other than fortune tellers, who knows what's next?