fix(player, frontend): use ScaleMode for screen

This commit is contained in:
Alex Kaminskii 2023-01-30 13:10:18 +01:00
parent 654682f4c9
commit da264f41f5
7 changed files with 71 additions and 72 deletions

View file

@ -7,21 +7,15 @@ import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite'
function Player() {
const [wrapperHeight, setWrapperHeight] = React.useState(0);
const playerContext = React.useContext(PlayerContext);
const screenWrapper = React.useRef<HTMLDivElement>(null);
const portHeight = playerContext.store.get().portHeight
React.useEffect(() => {
const parentElement = findDOMNode(screenWrapper.current) as HTMLDivElement | null; //TODO: good architecture
const parentElement = findDOMNode(screenWrapper.current) as HTMLDivElement | null;
if (parentElement) {
playerContext.player.attach(parentElement);
playerContext.player.play();
}
}, []);
React.useEffect(() => {
setWrapperHeight(portHeight)
}, [portHeight]);
if (!playerContext.player) return null;
@ -31,7 +25,7 @@ function Player() {
>
<div className={cn("relative flex-1", 'overflow-visible')}>
<Overlay isClickmap />
<div className={cn(stl.screenWrapper, '!overflow-y-scroll')} style={{ height: wrapperHeight, maxHeight: 800 }} ref={screenWrapper} />
<div className={cn(stl.screenWrapper, '!overflow-y-scroll')} style={{ maxHeight: 800 }} ref={screenWrapper} />
</div>
</div>
);

View file

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { createWebPlayer } from 'Player';
import { createClickMapPlayer } from 'Player';
import { makeAutoObservable } from 'mobx';
import withLocationHandlers from 'HOCs/withLocationHandlers';
import PlayerContent from './ThinPlayerContent';
@ -20,7 +20,7 @@ function WebPlayer(props: any) {
const [contextValue, setContextValue] = useState<IPlayerContext>(defaultContextValue);
useEffect(() => {
const [WebPlayerInst, PlayerStore] = createWebPlayer(customSession, (state) =>
const [WebPlayerInst, PlayerStore] = createClickMapPlayer(customSession, (state) =>
makeAutoObservable(state)
);
setContextValue({ player: WebPlayerInst, store: PlayerStore });
@ -35,9 +35,9 @@ function WebPlayer(props: any) {
contextValue.player && contextValue.player.play()
if (isPlayerReady && insights.size > 0) {
setTimeout(() => {
contextValue.player.jump(jumpTimestamp)
contextValue.player.pause()
contextValue.player.scaleFullPage()
contextValue.player.jump(jumpTimestamp)
contextValue.player.scale()
setTimeout(() => { contextValue.player.showClickmap(insights) }, 250)
}, 500)
}

View file

@ -27,6 +27,18 @@ export function createWebPlayer(session: Record<string, any>, wrapStore?: (s:IWe
}
export function createClickMapPlayer(session: Record<string, any>, wrapStore?: (s:IWebPlayerStore) => IWebPlayerStore): [IWebPlayer, IWebPlayerStore] {
let store: WebPlayerStore = new SimpleStore<WebState>({
...WebPlayer.INITIAL_STATE,
})
if (wrapStore) {
store = wrapStore(store)
}
const player = new WebPlayer(store, session, false, true)
return [player, store]
}
export function createLiveWebPlayer(session: Record<string, any>, config: RTCIceServer[], wrapStore?: (s:IWebLivePlayerStore) => IWebLivePlayerStore): [IWebLivePlayer, IWebLivePlayerStore] {
let store: WebLivePlayerStore = new SimpleStore<WebLiveState>({
...WebLivePlayer.INITIAL_STATE,

View file

@ -153,15 +153,18 @@ export default class Animator {
}
freeze() {
if (this.store.get().ready) {
// making sure that replay is displayed completely
setTimeout(() => {
this.store.update({ freeze: true })
this.pause()
}, 250)
} else {
setTimeout(() => this.freeze(), 500)
}
return new Promise<void>(res => {
if (this.store.get().ready) {
// making sure that replay is displayed completely
setTimeout(() => {
this.store.update({ freeze: true })
this.pause()
res()
}, 250)
} else {
setTimeout(() => res(this.freeze()), 500)
}
})
}
togglePlay = () => {

View file

@ -12,6 +12,13 @@ export const INITIAL_STATE: State = {
}
export enum ScaleMode {
Embed,
//AdjustParentWidth
AdjustParentHeight,
}
function getElementsFromInternalPoint(doc: Document, { x, y }: Point): Element[] {
// @ts-ignore (IE, Edge)
if (typeof doc.msElementsFromRect === 'function') {
@ -55,9 +62,9 @@ export default class Screen {
private readonly iframe: HTMLIFrameElement;
private readonly screen: HTMLDivElement;
private parentElement: HTMLElement | null = null;
private parentElement: HTMLElement | null = null
constructor(isMobile: boolean) {
constructor(isMobile: boolean, private scaleMode: ScaleMode = ScaleMode.Embed) {
const iframe = document.createElement('iframe');
iframe.className = styles.iframe;
this.iframe = iframe;
@ -79,11 +86,10 @@ export default class Screen {
attach(parentElement: HTMLElement) {
if (this.parentElement) {
this.parentElement = null
console.error("BaseScreen: Trying to attach an attached screen.");
console.warn("BaseScreen: reattaching the screen.");
}
parentElement.appendChild(this.screen);
this.parentElement = parentElement;
/* == For the Inspecting Document content == */
@ -124,6 +130,7 @@ export default class Screen {
private boundingRect: DOMRect | null = null;
private getBoundingClientRect(): DOMRect {
if (this.boundingRect === null) {
// TODO: use this.screen instead in order to separate overlay functionality
return this.boundingRect = this.overlay.getBoundingClientRect() // expensive operation?
}
return this.boundingRect
@ -200,48 +207,41 @@ export default class Screen {
if (!this.parentElement) return;
const { offsetWidth, offsetHeight } = this.parentElement;
this.scaleRatio = Math.min(offsetWidth / width, offsetHeight / height);
if (this.scaleRatio > 1) {
this.scaleRatio = 1;
} else {
this.scaleRatio = Math.round(this.scaleRatio * 1e3) / 1e3;
let translate = ""
let posStyles = {}
switch (this.scaleMode) {
case ScaleMode.Embed:
this.scaleRatio = Math.min(offsetWidth / width, offsetHeight / height)
translate = "translate(-50%, -50%)"
break;
case ScaleMode.AdjustParentHeight:
this.scaleRatio = offsetWidth / width
translate = "translate(-50%, 0)"
posStyles = { top: 0 }
break;
}
this.screen.style.transform = `scale(${ this.scaleRatio }) translate(-50%, -50%)`;
this.screen.style.width = width + 'px';
this.screen.style.height = height + 'px';
this.iframe.style.width = width + 'px';
this.iframe.style.height = height + 'px';
this.boundingRect = this.overlay.getBoundingClientRect();
}
scaleFullPage() {
if (!this.parentElement || !this.document) return;
const { width: boxWidth } = this.parentElement.getBoundingClientRect();
const { height, width } = this.document.body.getBoundingClientRect();
this.overlay.remove()
this.scaleRatio = boxWidth/width;
if (this.scaleRatio > 1) {
this.scaleRatio = 1;
} else {
this.scaleRatio = Math.round(this.scaleRatio * 1e3) / 1e3;
}
Object.assign(this.screen.style, {
top: '0',
left: '50%',
if (this.scaleMode === ScaleMode.AdjustParentHeight) {
this.parentElement.style.height = this.scaleRatio * height + 'px'
}
Object.assign(this.screen.style, posStyles, {
height: height + 'px',
width: width + 'px',
transform: `scale(${this.scaleRatio}) translate(-50%, 0)`,
transform: `scale(${this.scaleRatio}) ${translate}`,
})
Object.assign(this.iframe.style, {
width: width + 'px',
height: height + 'px',
})
return height
this.boundingRect = this.overlay.getBoundingClientRect();
}
}

View file

@ -6,7 +6,8 @@ import Player from '../player/Player'
import MessageManager from './MessageManager'
import InspectorController from './addons/InspectorController'
import TargetMarker from './addons/TargetMarker'
import Screen from './Screen/Screen'
import Screen, { ScaleMode } from './Screen/Screen'
// export type State = typeof WebPlayer.INITIAL_STATE
@ -17,7 +18,6 @@ export default class WebPlayer extends Player {
...MessageManager.INITIAL_STATE,
inspectorMode: false,
portHeight: 0,
}
private readonly inspectorController: InspectorController
@ -26,7 +26,7 @@ export default class WebPlayer extends Player {
private targetMarker: TargetMarker
constructor(protected wpState: Store<typeof WebPlayer.INITIAL_STATE>, session: any, live: boolean) {
constructor(protected wpState: Store<typeof WebPlayer.INITIAL_STATE>, session: any, live: boolean, isClickMap = false) {
let initialLists = live ? {} : {
event: session.events || [],
stack: session.stackEvents || [],
@ -40,7 +40,7 @@ export default class WebPlayer extends Player {
) || [],
}
const screen = new Screen(session.isMobile)
const screen = new Screen(session.isMobile, isClickMap ? ScaleMode.AdjustParentHeight : ScaleMode.Embed)
const messageManager = new MessageManager(session, wpState, screen, initialLists)
super(wpState, messageManager)
this.screen = screen
@ -71,20 +71,11 @@ export default class WebPlayer extends Player {
}
scale = () => {
console.log('called scale')
const { width, height } = this.wpState.get()
this.screen.scale({ width, height })
this.inspectorController.scale({ width, height })
// this.updateMarketTargets() ??
}
scaleFullPage = () => {
window.removeEventListener('resize', this.scale)
window.addEventListener('resize', this.scaleFullPage)
const portHeight = this.screen.scaleFullPage()
return this.wpState.update({ portHeight })
this.targetMarker.updateMarkedTargets()
}
// Inspector & marker
@ -119,12 +110,11 @@ export default class WebPlayer extends Player {
}
showClickmap = (...args: Parameters<TargetMarker['injectTargets']>) => {
this.freeze()
if (this.wpState.get().portHeight !== 0) {
this.targetMarker.injectTargets(...args)
} else {
setTimeout(() => this.showClickmap(...args), 500)
}
this.screen.overlay.remove() // hack. TODO: 1.split Screen functionalities (overlay, mounter) 2. separate ClickMapPlayer class that does not create overlay
this.targetMarker.injectTargets(...args)
this.freeze().then(() => {
this.targetMarker.updateMarkedTargets()
})
}
setMarkerClick = (...args: Parameters<TargetMarker['setOnMarkerClick']>) => {

View file

@ -50,7 +50,7 @@ export default class TargetMarker {
private readonly store: Store<State>,
) {}
updateMarketTargets() {
updateMarkedTargets() {
const { markedTargets } = this.store.get()
if (markedTargets) {
this.store.update({