From 4ac79e422129e654e48909017a50b066b2f587d1 Mon Sep 17 00:00:00 2001 From: pacien Date: Fri, 24 Aug 2018 01:39:40 +0200 Subject: Handle click and touch events --- appcache.js | 7 ++- index.html | 7 ++- pointless/viewer/screen.js | 110 ---------------------------------- pointless/viewer/screen/screen.js | 110 ++++++++++++++++++++++++++++++++++ pointless/viewer/screen/timer.js | 48 +++++++++++++++ pointless/viewer/stage.js | 85 -------------------------- pointless/viewer/stage/actions.js | 121 ++++++++++++++++++++++++++++++++++++++ pointless/viewer/stage/stage.js | 76 ++++++++++++++++++++++++ pointless/viewer/timer.js | 48 --------------- pointless/viewer/viewer.css | 1 + 10 files changed, 364 insertions(+), 249 deletions(-) delete mode 100644 pointless/viewer/screen.js create mode 100644 pointless/viewer/screen/screen.js create mode 100644 pointless/viewer/screen/timer.js delete mode 100644 pointless/viewer/stage.js create mode 100644 pointless/viewer/stage/actions.js create mode 100644 pointless/viewer/stage/stage.js delete mode 100644 pointless/viewer/timer.js diff --git a/appcache.js b/appcache.js index f200133..2e71164 100644 --- a/appcache.js +++ b/appcache.js @@ -35,9 +35,10 @@ class AppCache { "pointless/viewer/init.js", "pointless/viewer/viewer.js", "pointless/viewer/presentation.js", - "pointless/viewer/stage.js", - "pointless/viewer/screen.js", - "pointless/viewer/timer.js" + "pointless/viewer/stage/stage.js", + "pointless/viewer/stage/actions.js", + "pointless/viewer/screen/screen.js", + "pointless/viewer/screen/timer.js" ]; const appCache = this; diff --git a/index.html b/index.html index f2168ed..72ea974 100644 --- a/index.html +++ b/index.html @@ -82,9 +82,10 @@
- - - + + + + diff --git a/pointless/viewer/screen.js b/pointless/viewer/screen.js deleted file mode 100644 index bf7a049..0000000 --- a/pointless/viewer/screen.js +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Pointless Viewer, a web-based Beamer presentation viewer - * Copyright (C) 2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -"use strict"; - -class Screen { - constructor(window, secondary=false, withTimer=false) { - this.window = window; - this.secondary = secondary; - - this.canvasId = "screen"; - this.page = null; - - this.timer = withTimer ? new Timer(window) : null; - this.pageTurnCount = 0; - - this._registerListeners(); - this._hideWelcomeScreen(); - } - - setPage(page) { - if (this.pageTurnCount++ === 1 && this.timer != null) - this.timer.start(); - - this.page = page; - this._repaint(); - } - - _registerListeners() { - const self = this; - this.window.addEventListener("resize", function() { - self._repaint(); - }); - } - - _hideWelcomeScreen() { - const welcomeScreen = this.window.document.getElementById("welcomeScreen"); - welcomeScreen.style.display = "none"; - } - - _getScreenSize(ratio) { - const windowRatio = this.window.innerWidth / this.window.innerHeight; - const horizontalScaleFactor = ratio / windowRatio; - return { - width: this.window.innerWidth * Math.min(horizontalScaleFactor, 1), - height: this.window.innerHeight / Math.max(horizontalScaleFactor, 1) - }; - } - - _getSlideSizeRatio() { - const viewport = this.page.getViewport(1); - return (viewport.width / 2) / viewport.height; - } - - _newCanvas(width, height, xOffset, yOffset) { - const canvas = document.createElement("canvas"); - canvas.width = width; - canvas.height = height; - - const context = canvas.getContext("2d"); - context.transform(1, 0, 0, 1, xOffset, yOffset); - - return { canvas: canvas, context: context }; - } - - _showCanvas(canvas) { - const oldCanvas = this.window.document.getElementById(this.canvasId); - canvas.id = oldCanvas.id; - canvas.classList = oldCanvas.classList; - oldCanvas.replaceWith(canvas); - } - - _render(canvas, context, scaleFactor) { - const renderContext = { - canvasContext: context, - viewport: this.page.getViewport(scaleFactor) - }; - - const self = this; - this.page.render(renderContext).then(function() { - self._showCanvas(canvas); - }); - } - - _repaint() { - if (this.page == null) return; - - const screenRatio = this._getSlideSizeRatio(); - const { width, height } = this._getScreenSize(screenRatio); - const scaleFactor = height / this.page.getViewport(1).height; - const xOffset = this.secondary ? -width : 0; - const { canvas, context } = this._newCanvas(width, height, xOffset, 0); - this._render(canvas, context, scaleFactor); - } -} diff --git a/pointless/viewer/screen/screen.js b/pointless/viewer/screen/screen.js new file mode 100644 index 0000000..bf7a049 --- /dev/null +++ b/pointless/viewer/screen/screen.js @@ -0,0 +1,110 @@ +/* + * Pointless Viewer, a web-based Beamer presentation viewer + * Copyright (C) 2018 Pacien TRAN-GIRARD + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +"use strict"; + +class Screen { + constructor(window, secondary=false, withTimer=false) { + this.window = window; + this.secondary = secondary; + + this.canvasId = "screen"; + this.page = null; + + this.timer = withTimer ? new Timer(window) : null; + this.pageTurnCount = 0; + + this._registerListeners(); + this._hideWelcomeScreen(); + } + + setPage(page) { + if (this.pageTurnCount++ === 1 && this.timer != null) + this.timer.start(); + + this.page = page; + this._repaint(); + } + + _registerListeners() { + const self = this; + this.window.addEventListener("resize", function() { + self._repaint(); + }); + } + + _hideWelcomeScreen() { + const welcomeScreen = this.window.document.getElementById("welcomeScreen"); + welcomeScreen.style.display = "none"; + } + + _getScreenSize(ratio) { + const windowRatio = this.window.innerWidth / this.window.innerHeight; + const horizontalScaleFactor = ratio / windowRatio; + return { + width: this.window.innerWidth * Math.min(horizontalScaleFactor, 1), + height: this.window.innerHeight / Math.max(horizontalScaleFactor, 1) + }; + } + + _getSlideSizeRatio() { + const viewport = this.page.getViewport(1); + return (viewport.width / 2) / viewport.height; + } + + _newCanvas(width, height, xOffset, yOffset) { + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + + const context = canvas.getContext("2d"); + context.transform(1, 0, 0, 1, xOffset, yOffset); + + return { canvas: canvas, context: context }; + } + + _showCanvas(canvas) { + const oldCanvas = this.window.document.getElementById(this.canvasId); + canvas.id = oldCanvas.id; + canvas.classList = oldCanvas.classList; + oldCanvas.replaceWith(canvas); + } + + _render(canvas, context, scaleFactor) { + const renderContext = { + canvasContext: context, + viewport: this.page.getViewport(scaleFactor) + }; + + const self = this; + this.page.render(renderContext).then(function() { + self._showCanvas(canvas); + }); + } + + _repaint() { + if (this.page == null) return; + + const screenRatio = this._getSlideSizeRatio(); + const { width, height } = this._getScreenSize(screenRatio); + const scaleFactor = height / this.page.getViewport(1).height; + const xOffset = this.secondary ? -width : 0; + const { canvas, context } = this._newCanvas(width, height, xOffset, 0); + this._render(canvas, context, scaleFactor); + } +} diff --git a/pointless/viewer/screen/timer.js b/pointless/viewer/screen/timer.js new file mode 100644 index 0000000..21cd8b8 --- /dev/null +++ b/pointless/viewer/screen/timer.js @@ -0,0 +1,48 @@ +/* + * Pointless Viewer, a web-based Beamer presentation viewer + * Copyright (C) 2018 Pacien TRAN-GIRARD + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +"use strict"; + +class Timer { + constructor(window) { + this.display = window.document.getElementById("timer"); + this.startTime = null; + this._setDisplay(0); + } + + start() { + if (this.startTime != null) return; + this.startTime = Date.now(); + + const self = this; + setInterval(function() { + self._runTimer(); + }, 1000); + } + + _runTimer() { + const timeDelta = Math.floor((Date.now() - this.startTime) / 1000); + this._setDisplay(timeDelta); + } + + _setDisplay(seconds) { + const dateObj = new Date(null); + dateObj.setSeconds(seconds); + this.display.textContent = dateObj.toISOString().substr(11, 8); + } +} diff --git a/pointless/viewer/stage.js b/pointless/viewer/stage.js deleted file mode 100644 index 1772480..0000000 --- a/pointless/viewer/stage.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Pointless Viewer, a web-based Beamer presentation viewer - * Copyright (C) 2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -"use strict"; - -class Stage { - constructor(onReady, onNext, onPrevious) { - this.onNext = onNext; - this.onPrevious = onPrevious; - this.audienceScreen = null; - this.presenterScreen = null; - - this.projector = window.open(window.location.href, "_blank", "toolbar=0,location=0,menubar=0"); - if (this.projector == null) - alert("Please allow pop-ups, then refresh this page."); - - const self = this; - this.projector.addEventListener("load", function() { - self.audienceScreen = new Screen(self.projector, false, false); - self.presenterScreen = new Screen(window, true, true); - self._watchDetach(); - onReady(); - }); - - this._registerEventHandler(window); - this._registerEventHandler(this.projector); - } - - setPage(page) { - this.audienceScreen.setPage(page); - this.presenterScreen.setPage(page); - } - - _registerEventHandler(window) { - const self = this; - window.addEventListener("keydown", function(event) { - self._onCommand(event); - }) - } - - _onCommand(keyboardEvent) { - switch (keyboardEvent.key) { - case "Enter": - case " ": - case "ArrowRight": - case "n": - return this.onNext(); - - case "ArrowLeft": - case "p": - return this.onPrevious(); - } - } - - _watchDetach() { - const self = this; - window.addEventListener("beforeunload", function() { - self._setMessage(self.projector, "Controller detached"); - }); - - this.projector.addEventListener("beforeunload", function() { - self._setMessage(window, "Viewer detached"); - }); - } - - _setMessage(window, message) { - const messageBar = window.document.getElementById("message"); - messageBar.textContent = message; - } -} diff --git a/pointless/viewer/stage/actions.js b/pointless/viewer/stage/actions.js new file mode 100644 index 0000000..271d7b7 --- /dev/null +++ b/pointless/viewer/stage/actions.js @@ -0,0 +1,121 @@ +/* + * Pointless Viewer, a web-based Beamer presentation viewer + * Copyright (C) 2018 Pacien TRAN-GIRARD + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +"use strict"; + +class ActionEventHandler { + constructor(onNext, onPrevious) { + this.onNext = onNext; + this.onPrevious = onPrevious; + } +} + +class KeyboardEventHandler extends ActionEventHandler { + register(window) { + const self = this; + window.addEventListener("keydown", function(event) { + self._onCommand(event); + }) + } + + _onCommand(keyboardEvent) { + switch (keyboardEvent.key) { + case "Enter": + case " ": + case "ArrowRight": + case "n": + return this.onNext(); + + case "ArrowLeft": + case "p": + return this.onPrevious(); + } + } +} + +class MouseClickEventHandler extends ActionEventHandler { + register(window) { + const self = this; + window.addEventListener("click", function(event) { + self._onCommand(event); + }) + } + + _onCommand(mouseEvent) { + this.onNext(); + } +} + +class TouchSwipeEventHandler extends ActionEventHandler { + constructor(onNext, onPrevious) { + super(onNext, onPrevious); + this.touchStartEvent = null; + this.touchMoveEvent = null; + } + + register(window) { + const self = this; + + window.addEventListener("touchstart", function(event) { + event.preventDefault(); + self._onTouchStart(event); + }); + + window.addEventListener("touchmove", function(event) { + event.preventDefault(); + self._onTouchMove(event); + }); + + window.addEventListener("touchend", function(event) { + event.preventDefault(); + self._onTouchEnd(); + }); + + window.addEventListener("touchcancel", function(event) { + event.preventDefault(); + }); + } + + _onTouchStart(touchEvent) { + this.touchStartEvent = touchEvent; + } + + _onTouchMove(touchEvent) { + this.touchMoveEvent = touchEvent; + } + + _onTouchEnd() { + if (this.touchStartEvent == null || this.touchMoveEvent == null) return; + + const touchDown = this._xCoordinate(this.touchStartEvent); + const touchUp = this._xCoordinate(this.touchMoveEvent); + const xDelta = touchDown - touchUp; + + if (xDelta > 0) + this.onNext(); + else if (xDelta < 0) + this.onPrevious(); + + this.touchStartEvent = null; + this.touchMoveEvent = null; + } + + _xCoordinate(touchEvent) { + return touchEvent.touches[0].clientX; // first finger + } +} diff --git a/pointless/viewer/stage/stage.js b/pointless/viewer/stage/stage.js new file mode 100644 index 0000000..e9a2d38 --- /dev/null +++ b/pointless/viewer/stage/stage.js @@ -0,0 +1,76 @@ +/* + * Pointless Viewer, a web-based Beamer presentation viewer + * Copyright (C) 2018 Pacien TRAN-GIRARD + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +"use strict"; + +class Stage { + constructor(onReady, onNext, onPrevious) { + this.audienceScreen = null; + this.presenterScreen = null; + + this.projector = window.open(window.location.href, "_blank", "toolbar=0,location=0,menubar=0"); + if (this.projector == null) + alert("Please allow pop-ups, then refresh this page."); + + const self = this; + this.projector.addEventListener("load", function() { + self.audienceScreen = new Screen(self.projector, false, false); + self.presenterScreen = new Screen(window, true, true); + self._watchDetach(); + onReady(); + }); + + this.eventHandlers = [ + new KeyboardEventHandler(onNext, onPrevious), + new MouseClickEventHandler(onNext, onPrevious), + new TouchSwipeEventHandler(onNext, onPrevious) + ]; + + this._registerEventHandler(window); + this._registerEventHandler(this.projector); + } + + setPage(page) { + this.audienceScreen.setPage(page); + this.presenterScreen.setPage(page); + } + + _registerEventHandler(window) { + if (window == null) return; + + this.eventHandlers.forEach(function(eventHandler) { + eventHandler.register(window); + }); + } + + _watchDetach() { + const self = this; + window.addEventListener("beforeunload", function() { + self._setMessage(self.projector, "Controller detached"); + }); + + this.projector.addEventListener("beforeunload", function() { + self._setMessage(window, "Viewer detached"); + }); + } + + _setMessage(window, message) { + const messageBar = window.document.getElementById("message"); + messageBar.textContent = message; + } +} diff --git a/pointless/viewer/timer.js b/pointless/viewer/timer.js deleted file mode 100644 index 21cd8b8..0000000 --- a/pointless/viewer/timer.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Pointless Viewer, a web-based Beamer presentation viewer - * Copyright (C) 2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -"use strict"; - -class Timer { - constructor(window) { - this.display = window.document.getElementById("timer"); - this.startTime = null; - this._setDisplay(0); - } - - start() { - if (this.startTime != null) return; - this.startTime = Date.now(); - - const self = this; - setInterval(function() { - self._runTimer(); - }, 1000); - } - - _runTimer() { - const timeDelta = Math.floor((Date.now() - this.startTime) / 1000); - this._setDisplay(timeDelta); - } - - _setDisplay(seconds) { - const dateObj = new Date(null); - dateObj.setSeconds(seconds); - this.display.textContent = dateObj.toISOString().substr(11, 8); - } -} diff --git a/pointless/viewer/viewer.css b/pointless/viewer/viewer.css index 6702702..21d58cc 100644 --- a/pointless/viewer/viewer.css +++ b/pointless/viewer/viewer.css @@ -21,6 +21,7 @@ html, body { color: white; font-family: sans-serif; overflow: hidden; + touch-action: none; height: 100%; } -- cgit v1.2.3