Suppose I've got four fingers down: two fingers (1, 2) in element A and two (3, 4) in element B.
Suppose I then move finger 1 and finger 3.
I should be looking at a touchmove
event which will contain changedTouches
containing fingers 1 and 3.
However what will targetTouches
contain? Will it contain 1 and 2, or 3 and 4, or all 4?
It seems like the only way to provide enough info about the fact that 1 and 2 are on the same element and 3 and 4 are both on a different element is to send two touchmove
events.
I'm building a touch framework and I have been constructing a global datastructure that tracks all fingers and their targets so I do know what's going on but I was wondering if it was possible to skip doing this entirely if the targetTouches
events could provide me all the information necessary.
I tested it with touchstart
on my page:
document.touchstart = function(evt) { console.log("touchstart", evt.targetTouches); }
I put four fingers down in the order I described above. Next up I'll try to see if I can find out what targetTouches contains in touchmove
which is a more difficult task because of how much data it generates.
I will post my findings on iOS6.0 (iPhone 5), iOS5.1.1 (iPad 3), Nexus 7 on Android 4.2.1 (Chrome 18.0.1025469), and Firefox for Android 17 on the Nexus 7 below.
Currently only have data from the iPhone 5. This is a lot of work.
What I did was make two elements in the page and in the touchstart
call preventDefault()
to prevent scroll. Then I had touchmove
count the length of its changedTouches
and targetTouches
buffers and display that in the DOM. Furthermore, I counted the rate at which the events came in. Here's a snippet of the code:
// exposed is a variable which other code uses rAF to present a representation of it on the DOM so I can view it
touchmove: function(evt) {
evt.preventDefault();
var time = Date.now();
var diff = time - exposed.touch_move_last_time;
if (!exposed.touch_move_last_time) exposed.touch_move_last_time = Date.now();
if (!exposed.touch_move_rate) exposed.touch_move_rate = 0;
exposed.touch_move_last_time = time;
exposed.touch_move_rate += (diff - exposed.touch_move_rate)*0.01;
exposed.touch_move_changedTouches_count = evt.changedTouches.length;
exposed.touch_move_targetTouches_count = evt.targetTouches.length;
When I move my finger around, I move it in a circle rather than a zig-zag because at the zig-zag points it can fire fewer events than the sample rate. Due to the low rate of convergence (this is to produce numbers that don't keep fluctuating) it takes about 5 seconds of continued rubbing to get the reading to stabilize on the sample rate.
iOS6.0:
Put down two fingers in one element and move one finger around:
changedTouches
size: 1 (the one that moves)
targetTouches
size: 2 (the two fingers on the element)
sample rate: 16.66ms
Put down two fingers in one element and move both around:
changedTouches
size: 2 (both are moving)
targetTouches
size: 2 (the two fingers on the element)
sample rate: 16.66ms
Put down one finger in each element and move one finger around:
changedTouches
size: 1 (the one that moves)
targetTouches
size: 1 (refers to element initially touched by the one that moves)
sample rate: 16.66ms
Put down one finger in each element and move both fingers around:
changedTouches
size: 1 (the one that moves)
targetTouches
size: 1 (refers to element initially touched by the one moving)
sample rate: 8.29ms
Put down one finger in first element and two fingers in second element:
if moving one finger in the second element
changedTouches
size: 1
targetTouches
size: 2
sample rate: 16.66ms
if moving both fingers in the second element
changedTouches
size: 2
targetTouches
size: 2
sample rate: 16.6ms (really hard to keep the first finger not moving)
if moving the finger in the first element
changedTouches
size: 1
targetTouches
size: 1
sample rate: 16.66ms
if moving the finger in the first element and one finger in the second element
changedTouches
size: 1
targetTouches
size: fluctuates between 1 and 2
sample rate: 8.29ms
if moving all three fingers
changedTouches
size: fluctuates between 1 and 2
targetTouches
size: 2
sample rate: about 8.3ms
Put down two fingers in each element and move one in each element around:
changedTouches
size: 1
targetTouches
size: 2
sample rate: about 9ms
It's pretty clear that all cases where the sample rate is ~120Hz I had at least two elements that had fingers moving in it, which definitely seems to indicate that it will fire a separate touchmove
for each simultaneously touched element. I would bet that extending the test to 3 elements would see sample rates of 180Hz. Update: I tested 3 elements on the iPad and it does produce a 5.4ms reading.
What is a little curious to me is why I always get 8.29ms rather than 8.33ms exactly. The 9ms reading is probably just because it is more processing than it can handle at full speed (since I've got the DOM updating every frame)
Another Update:
On Chrome on the Nexus 7 the changedTouches
buffer always seems to be filled with all the touches because the webkitForce
reading is always changing for every single touch all the time. It is also so slow that the sample rate reading gives zero useful information. But by changing the number of fingers present in the last ordered element on the page it appears that the touchmove
events are also correctly being fired on a per-element basis.
Firefox on Nexus 7 is a bit better at producing reasonable sample rate readings but the updating of the display is even more sluggish than Chrome. Until Firefox becomes less choppy I don't consider it worth the effort of getting code working correctly on it.