-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathinputCoords.html
129 lines (118 loc) · 4.58 KB
/
inputCoords.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Input co-ordinate space test</title>
<style>
html {
margin: 0;
height: 5000px;
}
body {
margin: 0;
height: 100%;
width: 100%;
}
#content {
padding-top: 100px;
}
#client {
position: fixed;
background-color: red;
width: 28px;
height: 28px;
pointer-events: none;
}
#clientscroll {
position: absolute;
background-color: purple;
width: 22px;
height: 22px;
pointer-events: none;
}
#page {
position: absolute;
background-color: blue;
width: 16px;
height: 16px;
pointer-events: none;
}
#screen {
position: fixed;
background-color: green;
width: 10px;
height: 10px;
pointer-events: none;
}
</style>
</head>
<body>
<div id=client></div>
<div id=clientscroll></div>
<div id=page></div>
<div id=screen></div>
<div id=content>
There are four main coordinate systems exposed via JavaScript (all in units of "CSS pixels"):
<ol>
<li>Page coordinates: (0,0) represents the top-left of the document.</li>
<li>Client coordinates: (0,0) represents the top-left of the view the page is laid out into, the "layout viewport".</li>
<li>Visual coordinates: (0,0) represents the top-left of what the user sees - the <a href="https://dl.dropboxusercontent.com/u/4186806/viewport/index.html">visual viewport</a></li>
<li>Screen coordinates: (0,0) represents the top-left of the user's physical screen</li>
</ol>
<span style="color:red;">Red shows the client coordinates using position:fixed</span><br>
<span style="color:blue;">Blue shows the page coordinates using position:absolute</span><br>
<span style="color:purple;">Purple takes the client coordinates, adjusts them by the layout viewport position (documentElement.getBoundingClientRect) and shows the result relative to the page using position:absolute</span><br>
These three should work reliably virtually everywhere (except that position:fixed behaves strangely in Safari under pinch zoom)<br>
<br>
<span style="color:green;">Green attempts to map the screen co-ordinates onto the page but relies on heuristics to try to convert it to position:fixed values.</span> Known sources of error mapping screen co-ordinates to client co-ordinates include:<br> <ul>
<li>When embedded in an iframe, the frame's offset from the window</li>
<li>Pinch zoom / browser zoom scale</li>
<li>On mobile, the offset of the context in the screen (top controls, OS heading, etc.) and changes there to</li>
<li>Any reserved space at the bottom of the window (eg. developer tools)</li>
<li>Mobile (but not desktop) Safari uses device pixels instead of CSS pixels (fails to divide by the divicePixelRatio)</li>
</ul>
</div>
<script>
var cbox = document.getElementById('client');
var csbox = document.getElementById('clientscroll');
var pbox = document.getElementById('page');
var sbox = document.getElementById('screen');
for (var box of [cbox, pbox, csbox, sbox]) {
box.size = box.getBoundingClientRect().width;
}
var trackingTouch;
function handler(e) {
var coords = e;
if ('TouchEvent' in window && e instanceof TouchEvent) {
if (e.type == 'touchstart' && e.changedTouches.length == e.touches.length) {
// Track only the first finger
trackingTouch = e.touches[0].identifier;
coords = e.touches[0];
} else if (e.changedTouches[0].identifier == trackingTouch) {
coords = e.changedTouches[0];
} else {
return;
}
}
cbox.style.left = (coords.clientX - cbox.size/2) + 'px';
cbox.style.top = (coords.clientY - cbox.size/2) + 'px';
// Get the page location relative to the layout viewport
var pageViewport = document.documentElement.getBoundingClientRect();
csbox.style.left = (coords.clientX - csbox.size/2) - pageViewport.left + 'px';
csbox.style.top = (coords.clientY - csbox.size/2) - pageViewport.top + 'px';
pbox.style.left = (coords.pageX - pbox.size/2) + 'px';
pbox.style.top = (coords.pageY - pbox.size/2) + 'px';
// This is a heuristic, there's no reliable way to convert screen co-ordinates
if ('screenX' in window) {
var topHeight = window.outerHeight - window.innerHeight;
var borderSize = (window.outerWidth - window.innerWidth) / 2;
sbox.style.left = (coords.screenX - window.screenX - borderSize - sbox.size/2) + 'px';
sbox.style.top = (coords.screenY - window.screenY - topHeight + borderSize - sbox.size/2) + 'px';
}
}
for (var evt of ['touchstart', 'touchmove', 'touchend', 'mousedown', 'mousemove', 'mouseup'])
document.addEventListener(evt, handler);
</script>
</body>
</html>