From da264f41f565c7173afcb7cbf51078e8cdcf1cdd Mon Sep 17 00:00:00 2001 From: Alex Kaminskii Date: Mon, 30 Jan 2023 13:10:18 +0100 Subject: [PATCH] fix(player, frontend): use ScaleMode for screen --- .../Player/ClickMapRenderer/Renderer.tsx | 10 +--- .../Player/ClickMapRenderer/ThinPlayer.tsx | 8 +-- frontend/app/player/create.ts | 12 ++++ frontend/app/player/player/Animator.ts | 21 ++++--- frontend/app/player/web/Screen/Screen.ts | 60 +++++++++---------- frontend/app/player/web/WebPlayer.ts | 30 ++++------ .../app/player/web/addons/TargetMarker.ts | 2 +- 7 files changed, 71 insertions(+), 72 deletions(-) diff --git a/frontend/app/components/Session/Player/ClickMapRenderer/Renderer.tsx b/frontend/app/components/Session/Player/ClickMapRenderer/Renderer.tsx index a365dc163..8a51717e5 100644 --- a/frontend/app/components/Session/Player/ClickMapRenderer/Renderer.tsx +++ b/frontend/app/components/Session/Player/ClickMapRenderer/Renderer.tsx @@ -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(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() { >
-
+
); diff --git a/frontend/app/components/Session/Player/ClickMapRenderer/ThinPlayer.tsx b/frontend/app/components/Session/Player/ClickMapRenderer/ThinPlayer.tsx index 58ad80535..f903804f4 100644 --- a/frontend/app/components/Session/Player/ClickMapRenderer/ThinPlayer.tsx +++ b/frontend/app/components/Session/Player/ClickMapRenderer/ThinPlayer.tsx @@ -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(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) } diff --git a/frontend/app/player/create.ts b/frontend/app/player/create.ts index a07f3910d..016b8eb52 100644 --- a/frontend/app/player/create.ts +++ b/frontend/app/player/create.ts @@ -27,6 +27,18 @@ export function createWebPlayer(session: Record, wrapStore?: (s:IWe } +export function createClickMapPlayer(session: Record, wrapStore?: (s:IWebPlayerStore) => IWebPlayerStore): [IWebPlayer, IWebPlayerStore] { + let store: WebPlayerStore = new SimpleStore({ + ...WebPlayer.INITIAL_STATE, + }) + if (wrapStore) { + store = wrapStore(store) + } + + const player = new WebPlayer(store, session, false, true) + return [player, store] +} + export function createLiveWebPlayer(session: Record, config: RTCIceServer[], wrapStore?: (s:IWebLivePlayerStore) => IWebLivePlayerStore): [IWebLivePlayer, IWebLivePlayerStore] { let store: WebLivePlayerStore = new SimpleStore({ ...WebLivePlayer.INITIAL_STATE, diff --git a/frontend/app/player/player/Animator.ts b/frontend/app/player/player/Animator.ts index ab759bd50..e60b28d78 100644 --- a/frontend/app/player/player/Animator.ts +++ b/frontend/app/player/player/Animator.ts @@ -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(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 = () => { diff --git a/frontend/app/player/web/Screen/Screen.ts b/frontend/app/player/web/Screen/Screen.ts index 9283c4e4b..b095385b1 100644 --- a/frontend/app/player/web/Screen/Screen.ts +++ b/frontend/app/player/web/Screen/Screen.ts @@ -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(); } } diff --git a/frontend/app/player/web/WebPlayer.ts b/frontend/app/player/web/WebPlayer.ts index fb4386676..ba6f557b6 100644 --- a/frontend/app/player/web/WebPlayer.ts +++ b/frontend/app/player/web/WebPlayer.ts @@ -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, session: any, live: boolean) { + constructor(protected wpState: Store, 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) => { - 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) => { diff --git a/frontend/app/player/web/addons/TargetMarker.ts b/frontend/app/player/web/addons/TargetMarker.ts index bac17db8a..a31f5534e 100644 --- a/frontend/app/player/web/addons/TargetMarker.ts +++ b/frontend/app/player/web/addons/TargetMarker.ts @@ -50,7 +50,7 @@ export default class TargetMarker { private readonly store: Store, ) {} - updateMarketTargets() { + updateMarkedTargets() { const { markedTargets } = this.store.get() if (markedTargets) { this.store.update({