Audio scrubber jump to position working on desktop, but not on mobile

Hello Hype friends!

I have an audio scrubber that is supposed to jump to position when tapped. It works perfectly well on desktop browsers, but for some reason it doesn’t work on mobile browsers. Since it works when clicked with a mouse on desktop browsers, but not with a finger tap on mobile, I don’t see why it’s not working and wondering if it’s a bug or something? Is there some way to force the tap to be recognized on mobile browsers?

I’m triggering it with Hype’s native On Mouse Click (Tap) action.
The action runs the javascript function below called clickToTime():

function clickToTime () {
    var song = window['song' + window.counter];
	var sliderWidth = hypeDocument.getElementProperty(element, 'width');
 	var percentComplete = event.offsetX / sliderWidth;
 	// Find out the time of the location where the scrubber was clicked * song.duration());
    // Jump to that time in the scrubber and AutoScroll timelines

hypeDocument.goToTimeInTimelineNamed((hypeDocument.durationForTimelineNamed("Scrubber" + window.counter) * percentComplete), "Scrubber" + window.counter); 
hypeDocument.goToTimeInTimelineNamed((hypeDocument.durationForTimelineNamed("AutoScroll" + window.counter) * percentComplete), "AutoScroll" + window.counter);   

It’s as if the tap isn’t being recognized on mobile browsers and therefore the clickToTime() function isn’t even being run.

The easiest way to reproduce the error is with an iPad in landscape orientation (although the problem can be reproduced on iPhone as well - it’s just really small on the screen in landscape orientation so you may need to zoom in to be able to comfortably tap the audio scrubber to test).

To demonstrate the problem: when previewing on a mobile browser in landscape, if you tap the audio scrubber to jump fast forward or reverse, it is unresponsive - it doesn’t jump to position. If you try and click on the audio scrubber in a desktop browser, the click is recognized, the clickToTime() function is triggered and it jumps just fine. Quick side note: in this test file the audio track has been replaced with blank (silent) audio - don’t be alarmed if you play the track and don’t hear any sound.

Here is a test page online (where you can visit on desktop or mobile) to test the problem. And here is a link to download the Hype test file.

Any thoughts on what the problem might be and how to fix it would be so greatly appreciated! Any ideas?

Hi Raleigh!

I switched your choice of “On Mouse Click (Tap)” for the “ScrubberGroup” to “On Mouse Down (Touch Start)” and it worked fine on both my iPad & Desktop.


Hi @JimScott,

Thanks so much for your help!
I am heartened that it worked for you.
However, I’m also confused that it didn’t work for me!

I tried switching the “scrubberGroup” to “On Mouse Down (Touch Start)”.

In testing, it still works fine for me on desktop, but on my iPad Pro (2nd Gen 12.9) running iOS 12.1.1 it does’t work (still unresponsive on tap) while previewing on Hype reflect, mobile Safari, or mobile Chrome. I even made sure the cache was clean. Same results on my iPhone Xs running iOS 12.1.2 - no luck. :frowning:

I’m running Hype Pro version 3.6.7.

I’m curious - are you using the Hype Pro Beta (or a different version of Hype than me)?
Can you think of any reasons why it is working for you but no luck on any of my devices?

Hi Raleigh!

Unfortunate that we have this different result - it would be good for others to weigh in with their set-up (and results) to see if we can find the glitch.

For the record I am using; iPad 4th gen, iOS 10.3.3; Hype Pro v3.6.7 & Hype Reflect.

Agreed that it’s unfortunate that our results are different (although our iOS versions are a couple releases apart, interestingly).

This being the case, I wonder - did you happen to test whether or not the tapping to position on iOS worked for you “On Mouse Click (Tap)” the way I originally had it set up?
For me, it doesn’t work with either “On Mouse Click (Tap)” or “On Mouse Down (Touch Start)” on iOS. Wouldn’t it be interesting if it worked for you on both?

Thanks again for your input!

Also very curious what results others might have.
Thank you in advance to any other folks who are willing to try it!

Have you tried logging each of your expected values? On mobile devices, touch events are by default used instead of mouse events (Hype uses them to improve responsiveness in clicks). I think you’ll find that the event object for TouchEvents does not have an offsetX property, so that is probably causing the failures.

The easiest fix for something like this is typically to uncheck Use Touch Events in the Document Inspector. This causes mouse events to be used instead, which do have the offsetX property.

An alternative approach would be to still use touch events, but use the properties they do provide to derive an equivalent of offsetX (I recommend starting by logging the event object and I believe there are guides on how to properly get this via google).

1 Like

Hi @jonathan,

Thanks very much for your input!
I tried unchecking Use Touch Events and you are correct - it did indeed work.
Unfortunately (and not surprisingly), once unchecked, the difference in button responsiveness on mobile is so great that it makes all of the controls feel really sluggish and delayed.
I think (in this project at least) I’ll need to leave Use Touch Events left on in order to avoid the added latency.

I looked online to see what I could find for an equivalent of offsetX and these two articles (1, 2) jumped out.

They both seem to imply my only alternatives is to use clientX (which would be relative to the viewport), or screenX (which would be relative to the screen). In my case, in my clickToTime() function (included on my original post at the top of the thread) gets the percent complete based on dividing the event.offestX by the slider element’s width.

This being the case, can you offer any tips on how to modify my function so that I can use event.clientX or event.screenX and get my percentComplete based on the width of my slider element rather than relative to the viewport or the screen?

Not sure how best to implement this newfound information (but thankful the problem has been narrowed down, so thanks for that!).

Any further thoughts on how best to implement this into my clickToTime() function?
Thanks again!

Hi Raleigh!

Did a little research and I came up with the following: (12.5 KB)

This demo is only for a touch-based solution which I think could be integrated reasonably easily with your desktop mouse event code. I do not want to get too enthused just yet as previously the success of my iPad/iOS setup was at variance with your experience.


There are (2) functions in the demo:

initVars - calculates the left property of the “Slider Ensemble” group > global variable “sliderLocX”.

touchClientX - calculates the location on the “Slider Ensemble” that has been touched:

    var src = hypeDocument.getElementById("sliderEnsemble");
	var playheadEl = hypeDocument.getElementById("playhead");
	src.addEventListener('touchstart', function(e) {
	  xLoc = e.targetTouches[0].clientX;
	  xLoc = (xLoc - sliderLocX);
	  hypeDocument.setElementProperty(playheadEl,'left', xLoc, .5, 'easeinout');
	}, false);

Note: I did not create the equivalent of your “percentComplete” in this demo - but that should be fairly straightforward I would imagine as You have all the pertinent values.

1 Like

@JimScott, thanks so much for looking into this and putting the demo together!
I will give this a try and a close look. :slight_smile:
Thanks again and have a great weekend!

Hi Raleigh!

I just realized I uploaded the wrong version previously. The other version works but was not the intended upload. This version (v2) basically works the same - but all functions are fired “On Scene Load”… faster response from the initial touch on the slider. And some variables are changed… cleaner script.

And as long as I am uploading another version I added a “percentComplete” readout.

Replaces v1 above: (13.0 KB)

your slider is right simple. why not doing it the easy way:

set a range and oninput get a value … that’s it :slight_smile:

seems to me you’re (right often) attempting to complicate things which may be result of not being stable in js-scripting.

Hi @JimScott,

Thanks so much for this!
Works great on mobile.
I’ve got to teach for most of the day.
When I’m done I’m going to see if I can integrate this into my project!
Thanks again :slight_smile:

Hi @h_classen!

Thanks so much for your input on this.
I was thinking there must be some really simple way to do this, but I’m wondering:

In the link you provided, none of those sliders work on mobile either (which is the tap-to-position-on-mobile functionality I’m looking for on my slider).

Jim Scott’s solution seems to work well.
Is there a simpler way to get it to work than Jim Scott’s solution?

Thanks so much!

mea cul·pa, bad advice of mine … really thought rangeslider is standard, but yes the tap does not work on iOS!
there are a few libraries around to handle this, but then you#re really better of to script it within hype … so take @JimScott approach.

Of course, no worries at all. Thank you again for your thoughts.
Likewise, I’d have thought that tap functionality with rangesliders would be standard as well (especially in 2019, lol!). C’est la vie. :slight_smile:

Hi @JimScott,

I’ve been trying to integrate your code solution into my project and unfortunately I’m getting some odd behavior and I’m not sure why.

The issue I’m running up against is: when I test on mobile (or on Chrome with the dev tools visible and device set as iPhone), when I try to tap on a given location within my slider, the positioning is off.

For example, if I tap around what should be the 25% mark on the slider, the sliderPercent registers at .75. If I tap at what should be around the 50% mark, the sliderPercent registers at .88. Strange, right? All of the values are off.

I was thinking that it might be because my slider (named ScrubberGroup in my project) is nested in multiple elements. I actually tried moving my ScrubberGroup up a level (so that it was nested in only one group rather than two) and this did seem to change it for the better, but the location of the tap still didn’t register correctly. But the fact that changing the level of the nesting made a difference still makes be wonder if this is part of the issue.

It works so well in your example. I’d love to try and figure out why it’s not working like it does in your demo but I’m afraid I’ve exhausted all of my troubleshooting options.

Here is the test file I’m working with that has your code added. For troubleshooting ease, I consolidated the variable declarations into your touchClientX() function and also moved the triggering of the function to On Mouse Down (Touch Start) instead of On Layout Load.

Do you happen to have any thoughts on why the sliderPercent is so off and what it might take to get it aligned?

Thank you again for your time and consideration with this!
All the best.

Hi Raleigh!

It might be a day or two before I can look at your set-up.

Hi Jim,

Of course, no problem at all!
Thank you :slight_smile:

I found the problems... things went faster than I thought they might. :tada:

In order of importance:

#1 - You have two layouts for the Scene - but are using an id for your various elements. Multiple layouts in the same Scene will need to use Class for identification of the same element in both layouts.

#2 - Indeed, as You surmised, the "Group in a Group" is also causing a problem. However, easy to solve: Just move the "ScrubberGroup" out of the "Audio Controls" group. The reason this did not work when You tried this previously was the ID conflict as described in #1 creating inaccurate data.

OR - keeping the "ScrubberGroup" right where it is - factor in the "left" property of the "Audio Controls" group in addition to that of the "ScrubberGroup" for establishing the accurate "touch" location on the "ScrubberGroup".

A quick way to test these suggestions is to:

1) Eliminate the "custom" layout in the Scene (eliminates the "id" issue) - and then
2) Replace the "sliderLocX" term with "201" in the "touchClientX" function.

sliderGroup.addEventListener('touchstart', function(e) {
xLoc = e.targetTouches[0].clientX;
xLoc = (xLoc - sliderLocX); // replace with "201"
hypeDocument.setElementProperty(playheadEl,'left', xLoc, .0, 'easeinout');

Why "201"? Because it is the aggregate of the left properties of the "Audio Controls" group ("left: 138") and the "ScrubberGroup" ("left: 63"). You of course will want to have the script account for this situation rather than simply hard code the number as done here.


This is all fantastic. :slight_smile:
Thank you so much - awesome input and so very appreciated.
I will give this a shot!

1 Like