on master help sign in
Fix mouse and touch tracking for embedded Elm programs, #291
a29a1fdEvan Czaplicki
libraries/Native/Signal/Mouse.js+1−17
@@ -23,22 +23,6 @@ Elm.Native.Mouse.make = function(elm) {
23 var isClicked = Signal.constant(false);
23 var isClicked = Signal.constant(false);
24 var clicks = Signal.constant(Utils.Tuple0);
24 var clicks = Signal.constant(Utils.Tuple0);
25
25
26− function getXY(e) {
27− var posx = 0;
28− var posy = 0;
29− if (!e) e = window.event;
30− if (e.pageX || e.pageY) {
31− posx = e.pageX;
32− posy = e.pageY;
33− } else if (e.clientX || e.clientY) {
34− posx = e.clientX + document.body.scrollLeft +
35− document.documentElement.scrollLeft;
36− posy = e.clientY + document.body.scrollTop +
37− document.documentElement.scrollTop;
38− }
39− return Utils.Tuple2(posx-elm.node.offsetX, posy-elm.node.offsetY);
40− }
41−
42 var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
26 var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
43
27
44 elm.addListener([isClicked.id, clicks.id], node, 'click', function click() {
28 elm.addListener([isClicked.id, clicks.id], node, 'click', function click() {
@@ -53,7 +37,7 @@ Elm.Native.Mouse.make = function(elm) {
53 elm.notify(isDown.id, false);
37 elm.notify(isDown.id, false);
54 });
38 });
55 elm.addListener([position.id], node, 'mousemove', function move(e) {
39 elm.addListener([position.id], node, 'mousemove', function move(e) {
56− elm.notify(position.id, getXY(e));
40+ elm.notify(position.id, Utils.getXY(e));
57 });
41 });
58
42
59 return elm.Native.Mouse.values = {
43 return elm.Native.Mouse.values = {
libraries/Native/Signal/Touch.js+10−7
@@ -7,7 +7,7 @@ Elm.Native.Touch.make = function(elm) {
7
7
8 var Signal = Elm.Signal.make(elm);
8 var Signal = Elm.Signal.make(elm);
9 var JS = Elm.JavaScript.make(elm);
9 var JS = Elm.JavaScript.make(elm);
10− var _ = Elm.Native.Utils.make(elm);
10+ var Utils = Elm.Native.Utils.make(elm);
11
11
12 function Dict() {
12 function Dict() {
13 this.keys = [];
13 this.keys = [];
@@ -43,10 +43,11 @@ Elm.Native.Touch.make = function(elm) {
43
43
44 function touch(t) {
44 function touch(t) {
45 var r = dict.lookup(t.identifier);
45 var r = dict.lookup(t.identifier);
46+ var point = Utils.getXY(t);
46 return {_ : {},
47 return {_ : {},
47 id: t.identifier,
48 id: t.identifier,
48− x : t.pageX - elm.node.offsetX,
49+ x : point._0,
49− y : t.pageY - elm.node.offsetY,
50+ y : point._1,
50 x0: r.x,
51 x0: r.x,
51 y0: r.y,
52 y0: r.y,
52 t0: r.t
53 t0: r.t
@@ -56,9 +57,10 @@ Elm.Native.Touch.make = function(elm) {
56 var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
57 var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
57
58
58 function start(e) {
59 function start(e) {
60+ var point = Utils.getXY(e);
59 dict.insert(e.identifier,
61 dict.insert(e.identifier,
60− {x: e.pageX - elm.node.offsetX,
62+ {x: point._0,
61− y: e.pageY - elm.node.offsetY,
63+ y: point._1,
62 t: Date.now()});
64 t: Date.now()});
63 }
65 }
64 function end(e) {
66 function end(e) {
@@ -88,10 +90,11 @@ Elm.Native.Touch.make = function(elm) {
88
90
89 var mouseID = -1;
91 var mouseID = -1;
90 function move(e) {
92 function move(e) {
93+ var point = Utils.getXY(e);
91 for (var i = root.value.length; i--; ) {
94 for (var i = root.value.length; i--; ) {
92 if (root.value[i].id === mouseID) {
95 if (root.value[i].id === mouseID) {
93− root.value[i].x = e.pageX - elm.node.offsetX;
96+ root.value[i].x = point._0;
94− root.value[i].y = e.pageY - elm.node.offsetY;
97+ root.value[i].y = point._1;
95 elm.notify(root.id, root.value);
98 elm.notify(root.id, root.value);
96 break;
99 break;
97 }
100 }
libraries/Native/Utils.js+20−14
@@ -138,21 +138,26 @@ Elm.Native.Utils.make = function(elm) {
138 return Tuple2(w,h);
138 return Tuple2(w,h);
139 }
139 }
140
140
141− function adjustOffset() {
141+ function getXY(e) {
142− var node = elm.node;
142+ var posx = 0;
143− var offsetX = 0, offsetY = 0;
143+ var posy = 0;
144− if (node.offsetParent) {
144+ if (e.pageX || e.pageY) {
145− do {
145+ posx = e.pageX;
146− offsetX += node.offsetLeft;
146+ posy = e.pageY;
147− offsetY += node.offsetTop;
147+ } else if (e.clientX || e.clientY) {
148− } while (node = node.offsetParent);
148+ posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
149+ posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
149 }
150 }
150− elm.node.offsetX = offsetX;
151− elm.node.offsetY = offsetY;
152− }
153
151
154− if (elm.display === ElmRuntime.Display.COMPONENT) {
152+ if (elm.display === ElmRuntime.Display.COMPONENT) {
155− elm.addListener(elm.inputs, elm.node, 'mouseover', adjustOffset);
153+ var rect = elm.node.getBoundingClientRect();
154+ var relx = rect.left + document.body.scrollLeft + document.documentElement.scrollLeft;
155+ var rely = rect.top + document.body.scrollTop + document.documentElement.scrollTop;
156+ // TODO: figure out if there is a way to avoid rounding here
157+ posx = posx - Math.round(relx) - elm.node.clientLeft;
158+ posy = posy - Math.round(rely) - elm.node.clientTop;
159+ }
160+ return Tuple2(posx, posy);
156 }
161 }
157
162
158 return elm.Native.Utils.values = {
163 return elm.Native.Utils.values = {
@@ -172,6 +177,7 @@ Elm.Native.Utils.make = function(elm) {
172 min : F2(min),
177 min : F2(min),
173 mod : F2(mod),
178 mod : F2(mod),
174 htmlHeight: F2(htmlHeight),
179 htmlHeight: F2(htmlHeight),
180+ getXY: getXY,
175− toFloat: function(x){return x}
181+ toFloat: function(x) { return +x; }
176 };
182 };
177};
183};
runtime/Init.js−3
@@ -41,9 +41,6 @@ function init(display, container, module, moduleToReplace) {
41 return changed;
41 return changed;
42 }
42 }
43
43
44− container.offsetX = 0;
45− container.offsetY = 0;
46−
47 var listeners = [];
44 var listeners = [];
48 function addListener(relevantInputs, domNode, eventName, func) {
45 function addListener(relevantInputs, domNode, eventName, func) {
49 domNode.addEventListener(eventName, func);
46 domNode.addEventListener(eventName, func);