Skip to content

Make VR Image aspect ratio configurable with portrait override #2243

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
de:
pageflow_scrolled:
editor:
content_elements:
vrImage:
attributes:
aspectRatio:
blank: "(Automatisch)"
inline_help: Bestimmt die Form des VR-Panorama-Viewports. Automatisch verwendet optimierte Verhältnisse basierend auf der Elementbreite.
label: Seitenverhältnis
values:
narrow: Querformat (4:3)
portrait: Hochformat (9:16)
square: Quadrat (1:1)
wide: Querformat (16:9)
portraitAspectRatio:
blank: "(Standard)"
inline_help: Wird angezeigt, wenn das Browser-Viewport höher als breit ist, beispielsweise auf Telefonen oder Tablets im Hochformat. Kann verwendet werden, um ein anderes Seitenverhältnis bereitzustellen, das für die mobile Ansicht optimiert ist.
label: Seitenverhältnis (Hochkant)
values:
narrow: Querformat (4:3)
portrait: Hochformat (9:16)
square: Quadrat (1:1)
wide: Querformat (16:9)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
en:
pageflow_scrolled:
editor:
content_elements:
vrImage:
attributes:
aspectRatio:
blank: "(Auto)"
inline_help: Control the shape of the VR panorama viewport. Auto uses optimized ratios based on element width.
label: Aspect Ratio
values:
narrow: Landscape (4:3)
portrait: Portrait (9:16)
square: Square (1:1)
wide: Landscape (16:9)
portraitAspectRatio:
blank: "(Default)"
inline_help: Displayed when the browser viewport is taller than wide, for example on phones or tablets in portrait orientation. Can be used to provide a different aspect ratio optimized for mobile viewing.
label: Aspect Ratio (Portrait)
values:
narrow: Landscape (4:3)
portrait: Portrait (9:16)
square: Square (1:1)
wide: Landscape (16:9)
2 changes: 1 addition & 1 deletion entry_types/scrolled/package/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
node_modules
/editor.js
/frontend.js
/frontend
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import {getAspectRatio} from 'contentElements/vrImage/getAspectRatio';
import {contentElementWidths} from 'pageflow-scrolled/frontend';

describe('getAspectRatio', () => {
describe('when aspectRatio is not set (auto behavior)', () => {
it('returns 0.5 for full width', () => {
const result = getAspectRatio({
configuration: {},
contentElementWidth: contentElementWidths.full,
portraitOrientation: false
});

expect(result).toEqual(0.5);
});

it('returns 0.75 for non-full width', () => {
const result = getAspectRatio({
configuration: {},
contentElementWidth: contentElementWidths.md,
portraitOrientation: false
});

expect(result).toEqual(0.75);
});

it('returns 0.75 for non-full width when aspectRatio is null', () => {
const result = getAspectRatio({
configuration: {aspectRatio: null},
contentElementWidth: contentElementWidths.md,
portraitOrientation: false
});

expect(result).toEqual(0.75);
});
});

describe('when aspectRatio is set to specific value', () => {
it('returns correct ratio for wide', () => {
const result = getAspectRatio({
configuration: {aspectRatio: 'wide'},
contentElementWidth: contentElementWidths.md,
portraitOrientation: false
});

expect(result).toEqual(0.5625);
});

it('returns correct ratio for narrow', () => {
const result = getAspectRatio({
configuration: {aspectRatio: 'narrow'},
contentElementWidth: contentElementWidths.md,
portraitOrientation: false
});

expect(result).toEqual(0.75);
});

it('returns correct ratio for square', () => {
const result = getAspectRatio({
configuration: {aspectRatio: 'square'},
contentElementWidth: contentElementWidths.md,
portraitOrientation: false
});

expect(result).toEqual(1);
});

it('returns correct ratio for portrait', () => {
const result = getAspectRatio({
configuration: {aspectRatio: 'portrait'},
contentElementWidth: contentElementWidths.md,
portraitOrientation: false
});

expect(result).toEqual(1.7777);
});

it('returns 0.75 for unknown aspect ratio', () => {
const result = getAspectRatio({
configuration: {aspectRatio: 'unknown'},
contentElementWidth: contentElementWidths.md,
portraitOrientation: false
});

expect(result).toEqual(0.75);
});

it('uses specific aspect ratio even for full width', () => {
const result = getAspectRatio({
configuration: {aspectRatio: 'square'},
contentElementWidth: contentElementWidths.full,
portraitOrientation: false
});

expect(result).toEqual(1);
});
});

describe('portrait orientation behavior', () => {
it('uses portraitAspectRatio when in portrait orientation', () => {
const result = getAspectRatio({
configuration: {
aspectRatio: 'wide',
portraitAspectRatio: 'square'
},
contentElementWidth: contentElementWidths.md,
portraitOrientation: true
});

expect(result).toEqual(1);
});

it('uses portraitAspectRatio even when main aspectRatio is not set', () => {
const result = getAspectRatio({
configuration: {
portraitAspectRatio: 'portrait'
},
contentElementWidth: contentElementWidths.md,
portraitOrientation: true
});

expect(result).toEqual(1.7777);
});


it('falls back to main aspectRatio when portraitAspectRatio is not set', () => {
const result = getAspectRatio({
configuration: {aspectRatio: 'square'},
contentElementWidth: contentElementWidths.md,
portraitOrientation: true
});

expect(result).toEqual(1);
});

it('falls back to auto behavior when neither is set in portrait', () => {
const result = getAspectRatio({
configuration: {},
contentElementWidth: contentElementWidths.full,
portraitOrientation: true
});

expect(result).toEqual(0.5);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, {useRef, useState} from 'react';
import {useAutoCruising} from './useAutoCruising';
import {getAspectRatio} from './getAspectRatio';

import {
contentElementWidths,
useContentElementEditorState,
useContentElementLifecycle,
useFileWithInlineRights,
usePortraitOrientation,
ContentElementBox,
ContentElementFigure,
Panorama,
Expand All @@ -16,22 +17,25 @@ import {
export function VrImage({configuration, contentElementWidth}) {
const {shouldLoad} = useContentElementLifecycle();
const {isEditable, isSelected} = useContentElementEditorState();
const portraitOrientation = usePortraitOrientation();

const imageFile = useFileWithInlineRights({
configuration,
collectionName: 'imageFiles',
propertyName: 'image'
});

const aspectRatio = getAspectRatio({configuration, contentElementWidth, portraitOrientation});

return (
<div style={{pointerEvents: isEditable && !isSelected ? 'none' : undefined}}>
<FitViewport
aspectRatio={contentElementWidth === contentElementWidths.full ? 0.5 : 0.75}
aspectRatio={aspectRatio}
fill={configuration.position === 'backdrop'}>
<ContentElementBox>
<ContentElementFigure configuration={configuration}>
<FitViewport.Content>
{renderLazyPanorama(configuration, imageFile, shouldLoad)}
{renderLazyPanorama(configuration, imageFile, shouldLoad, aspectRatio)}
<InlineFileRights configuration={configuration}
context="insideElement"
items={[{file: imageFile, label: 'image'}]} />
Expand All @@ -46,9 +50,10 @@ export function VrImage({configuration, contentElementWidth}) {
);
}

function renderLazyPanorama(configuration, imageFile, shouldLoad) {
function renderLazyPanorama(configuration, imageFile, shouldLoad, aspectRatio) {
if (shouldLoad && imageFile && imageFile.isReady) {
return (<AutoCruisingPanorama imageFile={imageFile}
key={aspectRatio}
initialYaw={configuration.initialYaw}
initialPitch={configuration.initialPitch} />)
}
Expand Down
17 changes: 17 additions & 0 deletions entry_types/scrolled/package/src/contentElements/vrImage/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {SelectInputView, FileInputView, EnumTableCellView, SliderInputView, Sepa

import pictogram from './pictogram.svg';

const aspectRatios = ['wide', 'narrow', 'square', 'portrait'];

editor.contentElementTypes.register('vrImage', {
pictogram,
category: 'interactive',
Expand All @@ -28,6 +30,21 @@ editor.contentElementTypes.register('vrImage', {
minValue: -60,
maxValue: 60
});
this.input('aspectRatio', SelectInputView, {
includeBlank: true,
blankTranslationKey: 'pageflow_scrolled.editor.' +
'content_elements.vrImage.' +
'attributes.aspectRatio.blank',
values: aspectRatios
});
this.input('portraitAspectRatio', SelectInputView, {
includeBlank: true,
blankTranslationKey: 'pageflow_scrolled.editor.' +
'content_elements.vrImage.' +
'attributes.portraitAspectRatio.blank',
values: aspectRatios
});
this.view(SeparatorView);
this.group('ContentElementPosition');
this.view(SeparatorView);
this.group('ContentElementCaption', {entry});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {contentElementWidths} from 'pageflow-scrolled/frontend';

const aspectRatios = {
wide: 0.5625,
narrow: 0.75,
square: 1,
portrait: 1.7777
};

export function getAspectRatio({configuration, contentElementWidth, portraitOrientation}) {
const effectiveAspectRatio = portraitOrientation && configuration.portraitAspectRatio
? configuration.portraitAspectRatio
: configuration.aspectRatio;

if (!effectiveAspectRatio) {
return getAutoAspectRatio(contentElementWidth);
}

return aspectRatios[effectiveAspectRatio] || 0.75;
}

function getAutoAspectRatio(contentElementWidth) {
return contentElementWidth === contentElementWidths.full ? 0.5 : 0.75;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ storiesOfContentElement(module, {
initialPitch: 30
}
},
{
name: 'With custom aspect ratio',
configuration: {
aspectRatio: 'square'
}
},
{
name: 'Stereo image',
configuration: {
Expand Down
Loading