Fix joystick postion

- Aply new size after open and close iframe and permit to keep the good position of the joystick on the WorkAdventure screen
This commit is contained in:
Gregoire Parant 2021-08-04 18:07:04 +02:00
parent 238d5c22db
commit 190007a21f
2 changed files with 130 additions and 103 deletions

View File

@ -1,12 +1,12 @@
import VirtualJoystick from 'phaser3-rex-plugins/plugins/virtualjoystick.js'; import VirtualJoystick from "phaser3-rex-plugins/plugins/virtualjoystick.js";
import {waScaleManager} from "../Services/WaScaleManager"; import { waScaleManager } from "../Services/WaScaleManager";
import {DEPTH_INGAME_TEXT_INDEX} from "../Game/DepthIndexes"; import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes";
//the assets were found here: https://hannemann.itch.io/virtual-joystick-pack-free //the assets were found here: https://hannemann.itch.io/virtual-joystick-pack-free
export const joystickBaseKey = 'joystickBase'; export const joystickBaseKey = "joystickBase";
export const joystickBaseImg = 'resources/objects/joystickSplitted.png'; export const joystickBaseImg = "resources/objects/joystickSplitted.png";
export const joystickThumbKey = 'joystickThumb'; export const joystickThumbKey = "joystickThumb";
export const joystickThumbImg = 'resources/objects/smallHandleFilledGrey.png'; export const joystickThumbImg = "resources/objects/smallHandleFilledGrey.png";
const baseSize = 50; const baseSize = 50;
const thumbSize = 25; const thumbSize = 25;
@ -20,15 +20,27 @@ export class MobileJoystick extends VirtualJoystick {
x: -1000, x: -1000,
y: -1000, y: -1000,
radius: radius * window.devicePixelRatio, radius: radius * window.devicePixelRatio,
base: scene.add.image(0, 0, joystickBaseKey).setDisplaySize(baseSize * window.devicePixelRatio, baseSize * window.devicePixelRatio).setDepth(DEPTH_INGAME_TEXT_INDEX), base: scene.add
thumb: scene.add.image(0, 0, joystickThumbKey).setDisplaySize(thumbSize * window.devicePixelRatio, thumbSize * window.devicePixelRatio).setDepth(DEPTH_INGAME_TEXT_INDEX), .image(0, 0, joystickBaseKey)
.setDisplaySize(
(baseSize / waScaleManager.zoomModifier) * window.devicePixelRatio,
(baseSize / waScaleManager.zoomModifier) * window.devicePixelRatio
)
.setDepth(DEPTH_INGAME_TEXT_INDEX),
thumb: scene.add
.image(0, 0, joystickThumbKey)
.setDisplaySize(
(thumbSize / waScaleManager.zoomModifier) * window.devicePixelRatio,
(thumbSize / waScaleManager.zoomModifier) * window.devicePixelRatio
)
.setDepth(DEPTH_INGAME_TEXT_INDEX),
enable: true, enable: true,
dir: "8dir", dir: "8dir",
}); });
this.visible = false; this.visible = false;
this.enable = false; this.enable = false;
this.scene.input.on('pointerdown', (pointer: Phaser.Input.Pointer) => { this.scene.input.on("pointerdown", (pointer: Phaser.Input.Pointer) => {
if (!pointer.wasTouch) { if (!pointer.wasTouch) {
return; return;
} }
@ -44,7 +56,7 @@ export class MobileJoystick extends VirtualJoystick {
this.enable = false; this.enable = false;
} }
}); });
this.scene.input.on('pointerup', () => { this.scene.input.on("pointerup", () => {
this.visible = false; this.visible = false;
this.enable = false; this.enable = false;
}); });
@ -52,10 +64,16 @@ export class MobileJoystick extends VirtualJoystick {
this.scene.scale.on(Phaser.Scale.Events.RESIZE, this.resizeCallback); this.scene.scale.on(Phaser.Scale.Events.RESIZE, this.resizeCallback);
} }
private resize() { public resize() {
this.base.setDisplaySize(baseSize / waScaleManager.zoomModifier * window.devicePixelRatio, baseSize / waScaleManager.zoomModifier * window.devicePixelRatio); this.base.setDisplaySize(this.getDisplaySizeByElement(baseSize), this.getDisplaySizeByElement(baseSize));
this.thumb.setDisplaySize(thumbSize / waScaleManager.zoomModifier * window.devicePixelRatio, thumbSize / waScaleManager.zoomModifier * window.devicePixelRatio); this.thumb.setDisplaySize(this.getDisplaySizeByElement(thumbSize), this.getDisplaySizeByElement(thumbSize));
this.setRadius(radius / waScaleManager.zoomModifier * window.devicePixelRatio); this.setRadius(
(radius / (waScaleManager.zoomModifier * waScaleManager.uiScalingFactor)) * window.devicePixelRatio
);
}
private getDisplaySizeByElement(element: integer): integer {
return (element / (waScaleManager.zoomModifier * waScaleManager.uiScalingFactor)) * window.devicePixelRatio;
} }
public destroy() { public destroy() {

View File

@ -1,7 +1,8 @@
import {HtmlUtils} from "./HtmlUtils"; import { HtmlUtils } from "./HtmlUtils";
import {Subject} from "rxjs"; import { Subject } from "rxjs";
import {iframeListener} from "../Api/IframeListener"; import { iframeListener } from "../Api/IframeListener";
import {touchScreenManager} from "../Touch/TouchScreenManager"; import { touchScreenManager } from "../Touch/TouchScreenManager";
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
enum iframeStates { enum iframeStates {
closed = 1, closed = 1,
@ -9,13 +10,13 @@ enum iframeStates {
opened, opened,
} }
const cowebsiteDivId = 'cowebsite'; // the id of the whole container. const cowebsiteDivId = "cowebsite"; // the id of the whole container.
const cowebsiteMainDomId = 'cowebsite-main'; // the id of the parent div of the iframe. const cowebsiteMainDomId = "cowebsite-main"; // the id of the parent div of the iframe.
const cowebsiteAsideDomId = 'cowebsite-aside'; // the id of the parent div of the iframe. const cowebsiteAsideDomId = "cowebsite-aside"; // the id of the parent div of the iframe.
export const cowebsiteCloseButtonId = 'cowebsite-close'; export const cowebsiteCloseButtonId = "cowebsite-close";
const cowebsiteFullScreenButtonId = 'cowebsite-fullscreen'; const cowebsiteFullScreenButtonId = "cowebsite-fullscreen";
const cowebsiteOpenFullScreenImageId = 'cowebsite-fullscreen-open'; const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open";
const cowebsiteCloseFullScreenImageId = 'cowebsite-fullscreen-close'; const cowebsiteCloseFullScreenImageId = "cowebsite-fullscreen-close";
const animationTime = 500; //time used by the css transitions, in ms. const animationTime = 500; //time used by the css transitions, in ms.
interface TouchMoveCoordinates { interface TouchMoveCoordinates {
@ -24,7 +25,6 @@ interface TouchMoveCoordinates {
} }
class CoWebsiteManager { class CoWebsiteManager {
private opened: iframeStates = iframeStates.closed; private opened: iframeStates = iframeStates.closed;
private _onResize: Subject<void> = new Subject(); private _onResize: Subject<void> = new Subject();
@ -38,14 +38,14 @@ class CoWebsiteManager {
private resizing: boolean = false; private resizing: boolean = false;
private cowebsiteMainDom: HTMLDivElement; private cowebsiteMainDom: HTMLDivElement;
private cowebsiteAsideDom: HTMLDivElement; private cowebsiteAsideDom: HTMLDivElement;
private previousTouchMoveCoordinates: TouchMoveCoordinates|null = null; //only use on touchscreens to track touch movement private previousTouchMoveCoordinates: TouchMoveCoordinates | null = null; //only use on touchscreens to track touch movement
get width(): number { get width(): number {
return this.cowebsiteDiv.clientWidth; return this.cowebsiteDiv.clientWidth;
} }
set width(width: number) { set width(width: number) {
this.cowebsiteDiv.style.width = width+'px'; this.cowebsiteDiv.style.width = width + "px";
} }
get height(): number { get height(): number {
@ -53,7 +53,7 @@ class CoWebsiteManager {
} }
set height(height: number) { set height(height: number) {
this.cowebsiteDiv.style.height = height+'px'; this.cowebsiteDiv.style.height = height + "px";
} }
get verticalMode(): boolean { get verticalMode(): boolean {
@ -75,56 +75,55 @@ class CoWebsiteManager {
this.initResizeListeners(false); this.initResizeListeners(false);
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId); const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
buttonCloseFrame.addEventListener('click', () => { buttonCloseFrame.addEventListener("click", () => {
buttonCloseFrame.blur(); buttonCloseFrame.blur();
this.closeCoWebsite(); this.closeCoWebsite();
}); });
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId); const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
buttonFullScreenFrame.addEventListener('click', () => { buttonFullScreenFrame.addEventListener("click", () => {
buttonFullScreenFrame.blur(); buttonFullScreenFrame.blur();
this.fullscreen(); this.fullscreen();
}); });
} }
private initResizeListeners(touchMode:boolean) { private initResizeListeners(touchMode: boolean) {
const movecallback = (event:MouseEvent|TouchEvent) => { const movecallback = (event: MouseEvent | TouchEvent) => {
let x, y; let x, y;
if (event.type === 'mousemove') { if (event.type === "mousemove") {
x = (event as MouseEvent).movementX / this.getDevicePixelRatio(); x = (event as MouseEvent).movementX / this.getDevicePixelRatio();
y = (event as MouseEvent).movementY / this.getDevicePixelRatio(); y = (event as MouseEvent).movementY / this.getDevicePixelRatio();
} else { } else {
const touchEvent = (event as TouchEvent).touches[0]; const touchEvent = (event as TouchEvent).touches[0];
const last = {x: touchEvent.pageX, y: touchEvent.pageY}; const last = { x: touchEvent.pageX, y: touchEvent.pageY };
const previous = this.previousTouchMoveCoordinates as TouchMoveCoordinates; const previous = this.previousTouchMoveCoordinates as TouchMoveCoordinates;
this.previousTouchMoveCoordinates = last; this.previousTouchMoveCoordinates = last;
x = last.x - previous.x; x = last.x - previous.x;
y = last.y - previous.y; y = last.y - previous.y;
} }
this.verticalMode ? this.height += y : this.width -= x;
this.fire();
}
this.cowebsiteAsideDom.addEventListener( touchMode ? 'touchstart' : 'mousedown', (event) => { this.verticalMode ? (this.height += y) : (this.width -= x);
this.fire();
};
this.cowebsiteAsideDom.addEventListener(touchMode ? "touchstart" : "mousedown", (event) => {
this.resizing = true; this.resizing = true;
this.getIframeDom().style.display = 'none'; this.getIframeDom().style.display = "none";
if (touchMode) { if (touchMode) {
const touchEvent = (event as TouchEvent).touches[0]; const touchEvent = (event as TouchEvent).touches[0];
this.previousTouchMoveCoordinates = {x: touchEvent.pageX, y: touchEvent.pageY}; this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY };
} }
document.addEventListener(touchMode ? 'touchmove' : 'mousemove', movecallback); document.addEventListener(touchMode ? "touchmove" : "mousemove", movecallback);
}); });
document.addEventListener(touchMode ? 'touchend' : 'mouseup', (event) => { document.addEventListener(touchMode ? "touchend" : "mouseup", (event) => {
if (!this.resizing) return; if (!this.resizing) return;
if (touchMode) { if (touchMode) {
this.previousTouchMoveCoordinates = null; this.previousTouchMoveCoordinates = null;
} }
document.removeEventListener(touchMode ? 'touchmove' : 'mousemove', movecallback); document.removeEventListener(touchMode ? "touchmove" : "mousemove", movecallback);
this.getIframeDom().style.display = 'block'; this.getIframeDom().style.display = "block";
this.resizing = false; this.resizing = false;
}); });
} }
@ -132,34 +131,34 @@ class CoWebsiteManager {
private getDevicePixelRatio(): number { private getDevicePixelRatio(): number {
//on chrome engines, movementX and movementY return global screens coordinates while other browser return pixels //on chrome engines, movementX and movementY return global screens coordinates while other browser return pixels
//so on chrome-based browser we need to adjust using 'devicePixelRatio' //so on chrome-based browser we need to adjust using 'devicePixelRatio'
return window.navigator.userAgent.includes('Firefox') ? 1 : window.devicePixelRatio; return window.navigator.userAgent.includes("Firefox") ? 1 : window.devicePixelRatio;
} }
private close(): void { private close(): void {
this.cowebsiteDiv.classList.remove('loaded'); //edit the css class to trigger the transition this.cowebsiteDiv.classList.remove("loaded"); //edit the css class to trigger the transition
this.cowebsiteDiv.classList.add('hidden'); this.cowebsiteDiv.classList.add("hidden");
this.opened = iframeStates.closed; this.opened = iframeStates.closed;
this.resetStyle(); this.resetStyle();
} }
private load(): void { private load(): void {
this.cowebsiteDiv.classList.remove('hidden'); //edit the css class to trigger the transition this.cowebsiteDiv.classList.remove("hidden"); //edit the css class to trigger the transition
this.cowebsiteDiv.classList.add('loading'); this.cowebsiteDiv.classList.add("loading");
this.opened = iframeStates.loading; this.opened = iframeStates.loading;
} }
private open(): void { private open(): void {
this.cowebsiteDiv.classList.remove('loading', 'hidden'); //edit the css class to trigger the transition this.cowebsiteDiv.classList.remove("loading", "hidden"); //edit the css class to trigger the transition
this.opened = iframeStates.opened; this.opened = iframeStates.opened;
this.resetStyle(); this.resetStyle();
} }
public resetStyle() { public resetStyle() {
this.cowebsiteDiv.style.width = ''; this.cowebsiteDiv.style.width = "";
this.cowebsiteDiv.style.height = ''; this.cowebsiteDiv.style.height = "";
} }
private getIframeDom(): HTMLIFrameElement { private getIframeDom(): HTMLIFrameElement {
const iframe = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId).querySelector('iframe'); const iframe = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId).querySelector("iframe");
if (!iframe) throw new Error('Could not find iframe!'); if (!iframe) throw new Error("Could not find iframe!");
return iframe; return iframe;
} }
@ -167,9 +166,9 @@ class CoWebsiteManager {
this.load(); this.load();
this.cowebsiteMainDom.innerHTML = ``; this.cowebsiteMainDom.innerHTML = ``;
const iframe = document.createElement('iframe'); const iframe = document.createElement("iframe");
iframe.id = 'cowebsite-iframe'; iframe.id = "cowebsite-iframe";
iframe.src = (new URL(url, base)).toString(); iframe.src = new URL(url, base).toString();
if (allowPolicy) { if (allowPolicy) {
iframe.allow = allowPolicy; iframe.allow = allowPolicy;
} }
@ -183,15 +182,18 @@ class CoWebsiteManager {
const onTimeoutPromise = new Promise<void>((resolve) => { const onTimeoutPromise = new Promise<void>((resolve) => {
setTimeout(() => resolve(), 2000); setTimeout(() => resolve(), 2000);
}); });
this.currentOperationPromise = this.currentOperationPromise.then(() =>Promise.race([onloadPromise, onTimeoutPromise])).then(() => { this.currentOperationPromise = this.currentOperationPromise
this.open(); .then(() => Promise.race([onloadPromise, onTimeoutPromise]))
setTimeout(() => { .then(() => {
this.fire(); this.open();
}, animationTime) setTimeout(() => {
}).catch((err) => { this.fire();
console.error('Error loadCoWebsite => ', err); }, animationTime);
this.closeCoWebsite() })
}); .catch((err) => {
console.error("Error loadCoWebsite => ", err);
this.closeCoWebsite();
});
} }
/** /**
@ -200,56 +202,63 @@ class CoWebsiteManager {
public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise<void>): void { public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise<void>): void {
this.load(); this.load();
this.cowebsiteMainDom.innerHTML = ``; this.cowebsiteMainDom.innerHTML = ``;
this.currentOperationPromise = this.currentOperationPromise.then(() => callback(this.cowebsiteMainDom)).then(() => { this.currentOperationPromise = this.currentOperationPromise
this.open(); .then(() => callback(this.cowebsiteMainDom))
setTimeout(() => { .then(() => {
this.fire(); this.open();
}, animationTime); setTimeout(() => {
}).catch((err) => { this.fire();
console.error('Error insertCoWebsite => ', err); }, animationTime);
this.closeCoWebsite(); })
}); .catch((err) => {
console.error("Error insertCoWebsite => ", err);
this.closeCoWebsite();
});
} }
public closeCoWebsite(): Promise<void> { public closeCoWebsite(): Promise<void> {
this.currentOperationPromise = this.currentOperationPromise.then(() => new Promise((resolve, reject) => { this.currentOperationPromise = this.currentOperationPromise.then(
if(this.opened === iframeStates.closed) resolve(); //this method may be called twice, in case of iframe error for example () =>
this.close(); new Promise((resolve, reject) => {
this.fire(); if (this.opened === iframeStates.closed) resolve(); //this method may be called twice, in case of iframe error for example
const iframe = this.cowebsiteDiv.querySelector('iframe'); this.close();
if (iframe) { this.fire();
iframeListener.unregisterIframe(iframe); const iframe = this.cowebsiteDiv.querySelector("iframe");
} if (iframe) {
setTimeout(() => { iframeListener.unregisterIframe(iframe);
this.cowebsiteMainDom.innerHTML = ``; }
resolve(); setTimeout(() => {
}, animationTime) this.cowebsiteMainDom.innerHTML = ``;
})); resolve();
}, animationTime);
})
);
return this.currentOperationPromise; return this.currentOperationPromise;
} }
public getGameSize(): {width: number, height: number} { public getGameSize(): { width: number; height: number } {
if (this.opened !== iframeStates.opened) { if (this.opened !== iframeStates.opened) {
return { return {
width: window.innerWidth, width: window.innerWidth,
height: window.innerHeight height: window.innerHeight,
} };
} }
if (!this.verticalMode) { if (!this.verticalMode) {
return { return {
width: window.innerWidth - this.width, width: window.innerWidth - this.width,
height: window.innerHeight height: window.innerHeight,
} };
} else { } else {
return { return {
width: window.innerWidth, width: window.innerWidth,
height: window.innerHeight - this.height, height: window.innerHeight - this.height,
} };
} }
} }
private fire(): void { private fire(): void {
this._onResize.next(); this._onResize.next();
waScaleManager.applyNewSize();
} }
private fullscreen(): void { private fullscreen(): void {
@ -257,13 +266,13 @@ class CoWebsiteManager {
this.resetStyle(); this.resetStyle();
this.fire(); this.fire();
//we don't trigger a resize of the phaser game since it won't be visible anyway. //we don't trigger a resize of the phaser game since it won't be visible anyway.
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'inline'; HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = "inline";
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'none'; HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = "none";
} else { } else {
this.verticalMode ? this.height = window.innerHeight : this.width = window.innerWidth; this.verticalMode ? (this.height = window.innerHeight) : (this.width = window.innerWidth);
//we don't trigger a resize of the phaser game since it won't be visible anyway. //we don't trigger a resize of the phaser game since it won't be visible anyway.
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'none'; HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = "none";
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'inline'; HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = "inline";
} }
} }
} }