How to ask user to change orientation to portrait if he/she rotates phone to landscape mode

Thanks @DBear and @JimScott

I liked @DBear's solution because i dont have to add elements to every scene but @JimScott's version could be workable too - i have to try it.

I tried @DBear 's code and it worked like a charm. The only issue - and it is a big issue for me - is that if the device is already in landscape mode when the scene is loaded then it fails - the alert scene is not run. I tried to put the if-then condition in the function but it still breaks. I know I must be doing something stupid in my code but i cant figure out. Here is what i tried:

  var scene = "";
  
  scene = hypeDocument.currentSceneName();
  
  console.log(scene);
  
  document.querySelector('.scene-name').innerHTML = scene;

  window.addEventListener('orientationchange', function(event) {
  	if(window.innerHeight < window.innerWidth){
  		hypeDocument.showSceneNamed('alert', hypeDocument.kSceneTransitionPushLeftToRight, 0.3)
  	} else if (window.innerHeight > window.innerWidth){
  		hypeDocument.showSceneNamed(scene, hypeDocument.kSceneTransitionRightToLeft, 0.3)
  	}

	});
	
	if(window.innerHeight < window.innerWidth){
  		hypeDocument.showSceneNamed('alert', hypeDocument.kSceneTransitionPushLeftToRight, 0.3)
  	} else if (window.innerHeight > window.innerWidth){
  		hypeDocument.showSceneNamed(scene, hypeDocument.kSceneTransitionRightToLeft, 0.3)
  	}

Any ideas how to resolve this issue?
Is this issue because we are recursively calling scenes within scene load function? Should we use another eventlistener instead of directly loading other scenes within scene load functions?

@sgibm
I ran into the same problem with all of these approaches... but You didn't mention it as an issue for You until now. My assumption is that the listener is listening for a "change" in orientation. If the device starts out in landscape orientation there is no change to register, so the code does nothing.

As a work around I just simply fired the core aspect of the code_(window.innerHeight < window.innerWidth...)_
in the "On Scene Load". Problem: the code then runs for Desktops, etc. So you would need to check to see what device~user-agent before running the code.

Edit:
I reinserted the code again into "On Scene Load" (separate function) it works fine on initial load. Here is some info about testing for mobile devices.

if(window.innerHeight < window.innerWidth){
hypeDocument.getElementById('portraitAlert').style.display = "block";
} else if (window.innerHeight > window.innerWidth){
hypeDocument.getElementById('portraitAlert').style.display = "none";
}

Yes - if we just use the code without the listener for orientation change then it works initially but stops working for change in orientation by user later. The challenge is to make both things work simultaneously which for some reason does not work if i handle it the way i did in my code. In my code i added the if-then construct in addition to the event listener and it breaks. What do you think is causing that code to break? Maybe @DBear or @MarkHunte have some clue?

@sgibm

Here is my test piece that I’ve been using for this topic: orientationTest_v2.hype.zip (17.2 KB)

Both the initial check for orientation & the event listener are in the “Scene Load” handler. I’ve only used one scene in this trial. I will create a 2nd scene later to see if the functionality is impaired, right now I’m out of time.

Note: There are also some buttons in this project as part of another experiment, but it doesn’t impact the working result.

Hi @sgibm

Good catch on that bug. Here is another tweaked version of the code.

2 things.

  1. Create a New function (on Scene Load) and in it place the following:
V=0;

Basically we are creating a variable and initialising it to zero. I have used “V” for variable. It can be whichever letter you want.

  1. Create (or change the one you have) another function and in it put:

// take the original conditional and place it outside the listener and add on the condition "V==0". This is to stop it firing infinitely. Also add another condition the checks if the innerWidth is less than 1200 (for example) to stop it firing on a desktop.
if (window.innerWidth > window.innerHeight && window.innerWidth < 1200 && V==0) {
        hypeDocument.showSceneNamed('alert', hypeDocument.kSceneTransitionPushLeftToRight, 0.3)
    // Now increase the variable by 1 thus breaking the "loop"
        V++;
}

// here we have the original listener only we are gonna reload the scene (document)
window.addEventListener('orientationchange', function() {

    // every time we change orientation the scene will reload therefore firing this overall function all over again and the other function where the variable is initialised back to zero.
    location.reload();

});

This will take into account the innerWidth and innerHeight from the start thus checking the orientation and if it starts in landscae mode the conditional will play the “alert” scene. If it starts in a portrait position then it will do nothing.

3 Likes

@DBear
As usual You create such elegant solutions: In a small bit of code the need for checking for mobile devices is removed; the scene notice (i.e. scene named “alert”) is far better than creating an extra layout per scene, or even (as I was going to suggest), using a persistent symbol for the warning.

There is one thing in your coding that I felt penalized viewers. If they are deep in the scene navigation and, for what ever reason, rotate their device to landscape - your code requires them to start from scratch. No matter of consequence if returning to the scene is a click away (e.g. a button~menu selection) but if it is a progressive endeavor, it might be frustrating. The attached example let’s the viewer return to the scene at which they rotated their device to landscape - otherwise everything else is your code.

orientationTest_v4.hype.zip (51.9 KB)

Note: There is no "location.reload();" as in your code - I just return to the “var bookmarkScene” - (hypeDocument.showSceneNamed(bookmarkScene) which seems to work.

var bookmarkScene = hypeDocument.currentSceneName();
	if (window.innerWidth > window.innerHeight && window.innerWidth < 1200 && V==0) {
	        hypeDocument.showSceneNamed('alert');
	        V++;
	}
	  window.addEventListener('orientationchange', function() {
	  hypeDocument.showSceneNamed(bookmarkScene);	
	});  

===========

Separately:

I am a “designer that codes” & I have read and plowed through a plethora of intricate~dense monographs over many years; but the concise, lucid way You present solutions I think is exceptional; might You possibly consider curating the knowledge You have shared on this Forum in (digital) book form?

It is not just a matter of knowing the code - it is the strategies - that take things to another level; and this is the type of insight that is so often the essence of the questions on this Forum.

Just a thought…

3 Likes

cool, this is what i always was looking for :slight_smile:
thanx

1 Like

Brilliant! very concise code that does so much. The idea of the incremental variable is cool. It takes care of the recursion issue. I just have one issue now - when there are more than one scenes then the location.reload() takes you to the first scene irrespective of the scene the user was on. See attached hype doc.

orientationtest 2.zip (38.2 KB)

So I guess we might have to revert to storing the scene name. Or maybe there is another way?

Also wanted to know if “hype reflect” has an issue with the event listener. When i try it in larger projects with more scenes reflect’s screen turns blue and I have to test the site on safari for mobile instead. Anyone facing this issue?

@sgibm

I'll refer you to the post above as you may have missed it. I was just thinking of 1 page when I did my tweak but as @JimScott has done indeed you can use Hype's API to capture the scene name when it loads and instead of "re-loading" the entire document you can just show the same (or bookmarked) scene. Jim has given an example with the change

One thing to add and it's just to help with not having to add 2 functions in every scene and that is to condense it all into one. :slight_smile:

So here is the final code Jim's addition all in one function you can run on scene load :slight_smile:

        // addition by @JimScott (http://forums.tumult.com/users/JimScott)
	var bookmarkedScene = hypeDocument.currentSceneName();

	var V=0;
		
	// function for the check
	var detect = function () {
	
		if (window.innerWidth > window.innerHeight && window.innerWidth < 1200 && V==0) {
		        hypeDocument.showSceneNamed('alert');
		        V++;
		}
	}
	
	// call this immediateley to check if user is already in landscape mode
	detect();
	
	
	window.addEventListener('orientationchange', function() {
		
		// on orientation change take user back to the scene
		hypeDocument.showSceneNamed(bookmarkedScene);
		
	});

You are right. I missed that sentence of yours earlier.

The behavior is still not right for some reason beyond me. Can you take a look?

orientationtest 3.zip (38.1 KB)

When we change orientation to landscape the alert scene does not get triggered. And it gets trigerred when we switch back to portrait! This happens when we start off in portrait mode.

And if we start of in landscape mode then it shows alert scene but if we switch orientation, the alert scene remains on scene.

Have you set your viewport width to "device width" in the document inspector?

BTW @JimScott it has been considered however time is the enemy of us all and I feel I haven't got the time to do that just now. :slight_smile:

I am a "designer that codes" & I have read and plowed through a plethora of intricate~dense monographs over many years; but the concise, lucid way You present solutions I think is exceptional; might You possibly consider curating the knowledge You have shared on this Forum in (digital) book form?

It is not just a matter of knowing the code - it is the strategies - that take things to another level; and this is the type of insight that is so often the essence of the questions on this Forum.

Just a thought...

Thanks @DBear
The script works on a test project but when we tried using it on a production site it had a serious issue. After three to four orientation changes the scenes start getting sluggish and the alert scene loads several seconds after the actual orientation change and the browser even freezes after that.

Any idea what could be wrong? Tried to remove event listener on scene unload but even that didnt solve the sluggishness that happens after orientation changes in 3-4 scenes.

Just wondering if the persistent symbol idea is easier.

This has a persistent symbol hidden on each scene.

The Symbol runs the JS function.

	// call this immediateley to check if user is already in landscape mode
	detect();
	
	
	window.addEventListener('orientationchange', detect );
	
 function detect(){

console.log("here");
var thisSymbol = hypeDocument.getSymbolInstanceById('alert');

	if (window.innerWidth > window.innerHeight && window.innerWidth < 1200 ) {
		      hypeDocument.triggerCustomBehaviorNamed('alertShow')  
		 } else {
		 
		 hypeDocument.triggerCustomBehaviorNamed('alertHide')  
		}
		
}

To save messing about with getting a symbols instance I just created to two custom Behaviours alertHide, alertShow.

Which runs the symbols ‘alert’ timeline.

The timeline uses the display property to show or hide the alert rectangle.

I found that this did not get sluggish or freeze.
orientationtest_vMH1.hype.zip (29.1 KB)

2 Likes

@sgibm - Once You get us rollin’ there is no stopping us ;->

I did not have an issue with @DBear’s scene based approach to the rotation warning until I hit the 5th or 6th rotation in immediate succession which seems to be an excess unlikely to be done in “real life”. However…

As @MarkHunte suggested above, and I also mentioned in a previous post: using the persistent symbol.

I already created the following project yesterday, but when I read D’Bear’s post I felt it was a simpler implementation for the desired effect and so did not publish this example using a persistent symbol:
orientationTest_JHSv3a.hype.zip (43.8 KB)

Mark’s version certainly does the job well. The version I have posted includes the visual block of the content underneath & does not use a timeline. I have given it the torture test rotating it from one orientation to another over 20 times in immediate succession using all three scenes in the project - and as with Mark’s there is no sluggish behavior.

@sgibm - hopefully You will find something in these posts that works for You!

Edit Note: Replaced the “working” project originally uploaded here with a new version (v3a) that has the code cleaned up and extraneous bits & pieces removed.

4 Likes

Thanks @MarkHunte Nice use of behaviors. One isse i noticed is that in the first orientation change on scene 1 the red alert box appears below the blue box and button but subsequently on further orientation changes to landscape it fills up the screen. Any idea why this could be happening?

I will test this concept on some production site with more scenes etc. and update…

Thanks @JimScott. Really appreciate your input, time and effort and of @DBear, @MarkHunte who have contributed so much. I have learnt a lot and have found all approaches useful. I will test this concept in a production site and update if there is any issue.

On testing some of the approaches above i noticed that chrome on ios had issues with proper triggering of the orientationchange event listener. I tried resize in its place and it worked but it created other issues on pages with forms etc which automatically resize.

Is there any other alternative to make orientationchange work in chrome for ios?

Another issue I hit was that the alert pages sometimes loaded automatically zoomed in and when the orientation was changed back to portrait the portrait scene was also automatically zoomed in and after that it freezes. This happens on chrome for ios again. Any ideas/solutions?

What would be great is if in the Layouts section, one could specify both a Portrait AND a Landscape layout per tagged breakpoint where each would be triggered based on device orientation. The transition between each orientation could in itself trigger a mini-scene. Also, with either layout, different content/user capability could be enabled.

To be concise, the behind-the-scenes orientation management should be handled by Hype, not the user/developer/designer. :wink:

Not easy to do, you should add media query by pixel ratio / pixel density and not only by length.
This mean a lot of combinations; not only the IOS family but at least 10 other android devices. Moreover the iPad Pro is an hybrid with size like a laptop. In IOS devices some functions are not the same as the desktop ( parallax, fixed positions and so on) .
...difficult to manage, sorry but I see it really impossible

For the next version of Hype, I have added an API to allow developers to override Hype's behavior and make their own decisions on which layout to show when. Maybe there will be a common solution that can be shared (and then I can think of how to add it to Hype). Part of the "not easy to do" has to do with there being so many decisions that code is sometimes the best representation. I'm not sure that is the case here, but for now it will be flexible to allow any behaviors.

2 Likes