From f92289bc0a09ba42f43e533cb8bba9dc155a77b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janis=20Daniel=20Da=CC=88hne?= Date: Sat, 21 May 2022 16:02:44 +0200 Subject: [PATCH 1/2] - fixes issue #1529 - syc main and speaker view zoom --- js/config.js | 5 +- plugin/zoom/plugin.js | 106 +++++++++++++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 23 deletions(-) diff --git a/js/config.js b/js/config.js index 77da3057370..afd2c052ab8 100644 --- a/js/config.js +++ b/js/config.js @@ -275,6 +275,9 @@ export default { // viewDistance in order to save resources. mobileViewDistance: 2, + // if speak view and the normal view should sync the zoom + syncZoom: true, + // The display mode that will be used to show slides display: 'block', @@ -290,4 +293,4 @@ export default { // Plugin objects to register and use for this presentation plugins: [] -} \ No newline at end of file +} diff --git a/plugin/zoom/plugin.js b/plugin/zoom/plugin.js index 960fb810890..0cddebf58c1 100644 --- a/plugin/zoom/plugin.js +++ b/plugin/zoom/plugin.js @@ -1,41 +1,103 @@ /*! * reveal.js Zoom plugin */ -const Plugin = { +const Plugin = () => { + /** + * @typedef {Object} ZoomOptions + * @property {number} [scale] - the scaling factor + * @property {number} [x] - the x coordinate + * @property {number} [y] - the y coordinate + * @property {boolean} [pan] - is panning? + */ - id: 'zoom', + /** + * @typedef {Object} ZoomBroadcastMessage + * @property {("speaker"|"main")} source - the type of message + * @property {number} relativeX - relative x coordinate + * @property {number} relativeY - relative y coordinate + */ - init: function( reveal ) { + let isSpeakerView = false; //true: presenter/speaker view, false: main view + let isSpeakerPreviewFrame = false; //we only want to zoom in the main presenter frame (not presenter preview frame) + let broadcastChannel = new BroadcastChannel('zoom_channel'); - reveal.getRevealElement().addEventListener( 'mousedown', function( event ) { - var defaultModifier = /Linux/.test( window.navigator.platform ) ? 'ctrl' : 'alt'; + return { + id: 'zoom', - var modifier = ( reveal.getConfig().zoomKey ? reveal.getConfig().zoomKey : defaultModifier ) + 'Key'; - var zoomLevel = ( reveal.getConfig().zoomLevel ? reveal.getConfig().zoomLevel : 2 ); + init: function( reveal ) { - if( event[ modifier ] && !reveal.isOverview() ) { - event.preventDefault(); + const urlSearchParams = new URLSearchParams(window.location.search); + const params = Object.fromEntries(urlSearchParams.entries()); - zoom.to({ - x: event.clientX, - y: event.clientY, - scale: zoomLevel, - pan: false - }); - } - } ); + isSpeakerView = params.hasOwnProperty('receiver') - }, + //present html has a main view (iframe) and a preview next frame (iframe) + //preview don't have controls (so they are explicitly hidden) + isSpeakerPreviewFrame = isSpeakerView && !params.hasOwnProperty('controls') - destroy: () => { + reveal.getRevealElement().addEventListener( 'mousedown', function( event ) { + var defaultModifier = /Linux/.test( window.navigator.platform ) ? 'ctrl' : 'alt'; - zoom.reset(); + var modifier = ( reveal.getConfig().zoomKey ? reveal.getConfig().zoomKey : defaultModifier ) + 'Key'; + var zoomLevel = ( reveal.getConfig().zoomLevel ? reveal.getConfig().zoomLevel : 2 ); - } + if( event[ modifier ] && !reveal.isOverview() ) { + event.preventDefault(); + + /** @type {ZoomOptions} */ + let zoomOptions = { + x: event.clientX, + y: event.clientY, + scale: zoomLevel, + pan: false + }; + zoom.to(zoomOptions); + + if (reveal.getConfig().syncZoom) { + /** @type {ZoomBroadcastMessage} */ + const msg = { + source: isSpeakerView ? 'speaker' : 'main', + relativeX: event.clientX / document.body.clientWidth, + relativeY: event.clientY / document.body.clientHeight, + }; + broadcastChannel.postMessage(msg); + } + + } + } ); + + broadcastChannel.addEventListener('message', ( event) => { + if (isSpeakerView && !isSpeakerPreviewFrame) return //not zoom preview frame + + if (!reveal.getConfig().syncZoom) return + + var zoomLevel = ( reveal.getConfig().zoomLevel ? reveal.getConfig().zoomLevel : 2 ); + + /** @type ZoomBroadcastMessage */ + const msg = event.data; + + let zoomToOptions = { + x: msg.relativeX * document.body.clientWidth, + y: msg.relativeY * document.body.clientHeight, + scale: zoomLevel, + pan: false + } + zoom.to(zoomToOptions); + }) + + }, + + destroy: () => { + + zoom.reset(); + + } + + } }; -export default () => Plugin; +export default Plugin; /*! * zoom.js 0.3 (modified for use with reveal.js) From eba712cb22ebfde329371b4f887dbc7953c5e11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janis=20Daniel=20Da=CC=88hne?= Date: Sat, 21 May 2022 23:31:03 +0200 Subject: [PATCH 2/2] - speaker preview frame wrongly detected --- plugin/zoom/plugin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/zoom/plugin.js b/plugin/zoom/plugin.js index 0cddebf58c1..360254b072f 100644 --- a/plugin/zoom/plugin.js +++ b/plugin/zoom/plugin.js @@ -33,7 +33,7 @@ const Plugin = () => { //present html has a main view (iframe) and a preview next frame (iframe) //preview don't have controls (so they are explicitly hidden) - isSpeakerPreviewFrame = isSpeakerView && !params.hasOwnProperty('controls') + isSpeakerPreviewFrame = isSpeakerView && params.hasOwnProperty('controls') reveal.getRevealElement().addEventListener( 'mousedown', function( event ) { var defaultModifier = /Linux/.test( window.navigator.platform ) ? 'ctrl' : 'alt'; @@ -68,7 +68,7 @@ const Plugin = () => { broadcastChannel.addEventListener('message', ( event) => { - if (isSpeakerView && !isSpeakerPreviewFrame) return //not zoom preview frame + if (isSpeakerView && isSpeakerPreviewFrame) return //not zoom preview frame if (!reveal.getConfig().syncZoom) return