Responsive layouts, distinguish portrait and landscape

Hi,

i fiddled this for another thread in the frorum a few weeks ago and thought it might be worth a own topic.
just to be sure someone can find it when searching for a solution on this.

paste the following script to the head of the document and it will show a layout based on those rules:
on first place potrait or landscape is considered
on second place the breakpoints being set are considered
on third place the best matching layoutproportion of above …
if there’s no matching the hypedefaultlayout will be shown.

so for example you can create layouts with identical (or overlapping) breakpoints that are portrait or landscape and the script will show the best fitting for the given space in the document. This may be helpful with responsive ads …

<script>
function layoutRequest(hypeDocument, element, event) {


var pLayouts = [], hLayouts = [], destArray = [], debug = false;

var allLayouts = hypeDocument.layoutsForSceneNamed(hypeDocument.currentSceneName());

allLayouts.forEach(function(currentValue){
if(currentValue.width > currentValue.height){hLayouts.push(currentValue)}else{pLayouts.push(currentValue)}
})




var adWidth = window.innerWidth || (window.document.documentElement.clientWidth || window.document.body.clientWidth);

var adHeight = window.innerHeight || (window.document.documentElement.clientHeight || window.document.body.clientHeight);



if(adWidth > adHeight){
var layoutPool = hLayouts.sort(function(a,b){return a.breakpoint - b.breakpoint})
}else{
var layoutPool = pLayouts.sort(function(a,b){return a.breakpoint - b.breakpoint})
};

var tmpArray = [];
layoutPool.forEach(function(currentValue){

if(currentValue.breakpoint <= adWidth){
destArray.push(currentValue.name); 
tmpArray.push(currentValue.width/currentValue.height)
}

})



if(destArray.length === 1){
if(debug){console.log(destArray[0])};
return destArray[0]; 
}else if(destArray.length > 1){
if(debug){console.log(destArray)};
if(debug){console.log(tmpArray)};
if(debug){console.log(adWidth/adHeight)};
var index = closestIndex(tmpArray, adWidth/adHeight);
if(debug){console.log(destArray[index])};
return destArray[index]
}else{
return false
}


//////////

function closestIndex(array, nbr){

 smallestDiff = Math.abs(nbr - array[0]);
closest = 0; 

for (i = 1; i < array.length; i++) {
  currentDiff = Math.abs(nbr - array[i]);
  if (currentDiff < smallestDiff) {
smallestDiff = currentDiff;
closest = i;
  }
}
return closest;
}
//////////
  }

  if("HYPE_eventListeners" in window === false) {
window.HYPE_eventListeners = Array();
  }
  window.HYPE_eventListeners.push({"type":"HypeLayoutRequest", "callback":layoutRequest});
</script>

Hope this’ll work :slight_smile:
Have a best day!

11 Likes

Hello!

I’ve trying this and works great! Thank you very much for sharing this. :slight_smile:

Only size I can’t represent in my document is 200x200. It takes the vertical design instead of the small square that works great for 180x150.

Looks like

Wish it looked like

May it be that square sizes are problematic, since both sizes are equal? How does the script choose the right option?

1 Like

this’ll add square sizes to horizontal layouts pool. so if the breakpoint allows showing … it’ll show the matching horizontal layout instead of the portraitlayout:

<script>
	
function layoutRequest(hypeDocument, element, event) {


var pLayouts = [], hLayouts = [], destArray = [], debug = true;

var allLayouts = hypeDocument.layoutsForSceneNamed(hypeDocument.currentSceneName());

allLayouts.forEach(function(currentValue){
if(currentValue.width >= currentValue.height){hLayouts.push(currentValue)}else{pLayouts.push(currentValue)}
})




var adWidth = window.innerWidth || (window.document.documentElement.clientWidth || window.document.body.clientWidth);

var adHeight = window.innerHeight || (window.document.documentElement.clientHeight || window.document.body.clientHeight);



if(adWidth >= adHeight){
var layoutPool = hLayouts.sort(function(a,b){return a.breakpoint - b.breakpoint})
}else{
var layoutPool = pLayouts.sort(function(a,b){return a.breakpoint - b.breakpoint})
};

var tmpArray = [];
layoutPool.forEach(function(currentValue){

if(currentValue.breakpoint <= adWidth){
destArray.push(currentValue.name);
tmpArray.push(currentValue.width/currentValue.height)
}

})



if(destArray.length === 1){
if(debug){console.log(destArray[0])};
return destArray[0];
}else if(destArray.length > 1){
if(debug){console.log(destArray)};
if(debug){console.log(tmpArray)};
if(debug){console.log(adWidth/adHeight)};
var index = closestIndex(tmpArray, adWidth/adHeight);
if(debug){console.log(destArray[index])};
return destArray[index]
}else{
return false
}


//////////

function closestIndex(array, nbr){

 smallestDiff = Math.abs(nbr - array[0]);
closest = 0;

for (i = 1; i < array.length; i++) {
  currentDiff = Math.abs(nbr - array[i]);
  if (currentDiff < smallestDiff) {
smallestDiff = currentDiff;
closest = i;
  }
}
return closest;
}
//////////
  }

  if("HYPE_eventListeners" in window === false) {
window.HYPE_eventListeners = Array();
  }
  window.HYPE_eventListeners.push({"type":"HypeLayoutRequest", "callback":layoutRequest});
</script>

thx for testing :slight_smile:

7 Likes

In my latest testing, results that the container is 1px bigger that it should be. For instance, the border in the ad is not showing all around, but only in two of the borders as can be seen here.

Is it something in the layout that takes 1px?

the script just shows layouts … there’s no further modifying

That’s interesting! :slight_smile: Someone stole a pixel and can’t find the thief.

2 Likes

not stolen … instead there are a few more :slight_smile:

2 Likes

Amazing! This works a charm, and allows me to create separate portrait and landscape layouts for different sized devices, with elements appearing in different places in portrait vs landmark. IMHO, solves my issues much more easily than the flexible layouts. If I could nominate you for a Nobel prize in scripting, I would. Thanks, and kudos for such an elegant solution!

4 Likes

I have a follow-up on my progress, and an issue I am hoping can be resolved.

I created the following layouts:

iPhone Layouts:

Portrait, 375x667, breakpoint 320
Portrait, 414x736, breakpoint 414
Landscape, 667x375, breakpoint 667
Landscape, 736x414, breakpoint 736

iPad Layouts:

Portrait, 768x1024, breakpoint 768
Landscape, 1024x768, breakpoint 1024
Landscape, 1366x1024, breakpoint 1366

Now, all worked great at this point, at least using Safari and Responsive Design Mode.

But…When I added the following:

Portrait, 1024x1366, breakpoint 1024

I get all kinds of issues with other layouts automatically resizing themselves in Hype, and failure to recognize layouts in Safari.

Is there some way I can address this? I am assuming it is because instead of overlap, which I had originally, I have two layouts with the same breakpoint, even if one is Portrait and one is Landscape.

Thanks!

hm, the script does nothing to hype itsself

can you approve that all your layoutnames are unique¿

it did the effort setting up a simular document myself -> behaves as expected here
could you please test ...
layoutRequestTest.hype.zip (39.0 KB)

sunny and cold in western germany :slight_smile:

2 Likes

Thanks, Hans-Gerd!

Thank you, I checked to make sure every layout has a different name.

I changed one breakpoint as follows

From:

Portrait, 768x1024, breakpoint 768
Landscape, 1024x768, breakpoint 1024
Landscape, 1366x1024, breakpoint 1366

To:

Portrait, 768x1024, breakpoint 768
Landscape, 1024x768, breakpoint 1023
Landscape, 1366x1024, breakpoint 1366

So now the Landscape, 736x414, breakpoint 736 layout says, ‘736 to 1023,’ and that seems to have fixed it.

BUT…

Now I have a different issue, sorry to say. All they layouts work great in Safari in Responsive Design mode for iPhones and iPads. When I do NOT use Responsive Design mode, and just view the Hype document on my desktop, I get the following behavior:

First of all, its a MacBook Pro, late 2016, screen size horizontal 1680 px.

With Safari covering most of the display (not set to full-screen, but nearly filling the display), the Hype document shows up as an iPhone Landscape layout, with a breakpoint of 736 px. If I drag the Safari window smaller, at about 1480 px, the largest iPad landscape layout appears. Then, as I keep dragging the window smaller, other appropriate layouts appear.

So how to do I convince the largest iPad layout to be the default above 1480 px, for a desktop browser?

Again, I cannot thank you enough for a great piece of work. My document will look great on so many devices, Thanks!

Scott

Hans, here is a layout template modified from yours.

This one makes it easier to diagnose flexible reponsive problems.

Layout Test Template.hype.zip (71.2 KB)

1 Like

well, instead of looking for the best matching ratio within layouts matching portrait or landscape and breakpoints you could simply take the biggest breakpoint from matching portrait or landscape …

<script>

	function layoutRequest(hypeDocument, element, event) {


var pLayouts = [], hLayouts = [], destArray = [], debug = true;

var allLayouts = hypeDocument.layoutsForSceneNamed(hypeDocument.currentSceneName());

allLayouts.forEach(function(currentValue){
if(currentValue.width >= currentValue.height){hLayouts.push(currentValue)}else{pLayouts.push(currentValue)}
})



var adWidth = window.innerWidth || (window.document.documentElement.clientWidth || window.document.body.clientWidth);

var adHeight = window.innerHeight || (window.document.documentElement.clientHeight || window.document.body.clientHeight);



if(adWidth >= adHeight){
var layoutPool = hLayouts.sort(function(a,b){return a.breakpoint - b.breakpoint})
}else{
var layoutPool = pLayouts.sort(function(a,b){return a.breakpoint - b.breakpoint})
};



layoutPool.forEach(function(currentValue){
if(currentValue.breakpoint <= adWidth){
destArray.push(currentValue);
}

})

destArray = destArray.sort(function(a,b){return a.breakpoint - b.breakpoint})

if(destArray.length === 1){
if(debug){console.log(destArray[0].name)};
return destArray[0].name;
}else if(destArray.length > 1){
if(debug){console.log(destArray[destArray.length-1].name)};
return destArray[destArray.length-1].name
}else{
return false
}


//////////
  }

  if("HYPE_eventListeners" in window === false) {
window.HYPE_eventListeners = Array();
  }
  window.HYPE_eventListeners.push({"type":"HypeLayoutRequest", "callback":layoutRequest});
</script>
3 Likes

Ken-

That’s very helpful. What I found is that as I resize my browser window, the largest layout is replaced by two smaller layouts with wider aspect ratios.

Using this, I created a layout with a wider aspect ratio, and kept adjusting it to get the maximum browser window size. I found that at 1366x774, the new layout appears with a breakpoint at 1367, and persists until the window is near its max width. At that point, 736x414 appears briefly, then 667x375.

Is there a setting to ignore the aspect ratio, or to ignore the vertical distance? I couldn’t find any.


Hans-Gerd-

Thanks again, but I must be slow today, but I could not figure out what you were teaching.

I can tell you that everything is working great, and I am hesitant to change anything, but the final piece of the puzzle is figuring out why smaller layouts with wider aspect ratios appear at large window sizes, rather than those designed at larger break points. As I noted above, if I create a layout with my largest breakpoint, in my case 1367, I can see the new layout, but only up to a certain window width, after which iPhone landscape layouts appear, possible because their width: height ratio is higher than my layout at a large breakpoint.

I don’t know if this is helpful, I hope so.

Scott

Hans-Gerd-

I replaced the prior script with this one, and it works great! While I don’t understand what conceptual changes you made, the process just became much more accurate and precise. Awesome!

Scott

1 Like

hi, the aim for the original script was not your use case. its been meant for ads. various sizes for those are often quite near … that’s where the approach using the ratio came from …