From 30a95fef812b84f58189688f6cf3463b579991e1 Mon Sep 17 00:00:00 2001 From: niraularohan Date: Fri, 26 Jan 2024 22:39:32 +0545 Subject: [PATCH 01/10] a little unfinished but kinda working update --- extension/pinch-zoom.js | 406 ++++++++++++++++------------------------ 1 file changed, 160 insertions(+), 246 deletions(-) diff --git a/extension/pinch-zoom.js b/extension/pinch-zoom.js index f0889e3..5fb33a8 100644 --- a/extension/pinch-zoom.js +++ b/extension/pinch-zoom.js @@ -1,25 +1,4 @@ -/** -EDITED FOR THE PURPOSE OF USING WITH CHROME ON LINUX -ONLY SHIFT+SCROLL FUNCTIONALITY IMPLEMENTED - -Multi-touch zoom extension for Firefox -Enables smooth pinch to zoom on desktop - -Requires Firefox 55 or greater - -@Author: George Corney / haxiomic -@Website: http://github.com/haxiomic -@Email: haxiomic@gmail.com - -Please report issues to the github repository - https://github.com/haxiomic/firefox-multi-touch-zoom - -Feel free to get in touch via email if you have any questions - -**/ - -// view scaling parameters and other options -const scaleMode = 1; // 0 = always high quality, 1 = low-quality while zooming +const scaleMode = 1; const minScale = 1.0; const maxScale = 10; const zoomSpeedMultiplier = 0.03 / 5; @@ -27,23 +6,20 @@ const overflowTimeout_ms = 400; const highQualityWait_ms = 40; const alwaysHighQuality = false; -let horizontalOriginShift = 0; // > 0 to the right, < 0 to the left -let verticalOriginShift = 0; // > 0 down, < 0 up +let horizontalOriginShift = 0; +let verticalOriginShift = 0; let originMoveRate = 10; -// settings -let shiftKeyZoom = true; // enable zoom with shift + scroll by default +let shiftKeyZoom = true; let pinchZoomSpeed = 0.7; let disableScrollbarsWhenZooming = false; -// state let pageScale = 1; let translationX = 0; let translationY = 0; let overflowTranslationX = 0; let overflowTranslationY = 0; -// elements let pageElement = document.documentElement; let wheelEventElement = document.documentElement; let scrollEventElement = window; @@ -54,291 +30,229 @@ function getScrollBoxElement() { return document.documentElement || document.body; } -// apply user settings -chrome.storage.local.get([ - 'mtzoom_shiftkey', - 'mtzoom_speed', - 'mtzoom_disableScrollbarsWhenZooming', -], function (res) { - if (res.mtzoom_shiftkey != null) { - shiftKeyZoom = res.mtzoom_shiftkey; - } - if (res.mtzoom_speed != null) { - pinchZoomSpeed = res.mtzoom_speed; - } - if (res.mtzoom_disableScrollbarsWhenZooming != null) { - disableScrollbarsWhenZooming = res.mtzoom_disableScrollbarsWhenZooming; - } -}); - -// browser-hint optimization - I found this causes issues with some sites like maps.google.com -// pageElement.style.willChange = 'transform'; - - let mouseX, mouseY; -let shoudFollowMouse = false; +let shouldFollowMouse = false; let canFollowMouse = false; - document.onmousemove = (e) => { - if(!canFollowMouse) return; - if (shoudFollowMouse && mouseX && mouseY) { - //window.scrollBy(e.clientX - mouseX, e.clientY - mouseY); - horizontalOriginShift+= e.clientX - mouseX; - verticalOriginShift+= e.clientY - mouseY; - + if (!canFollowMouse) return; + if (shouldFollowMouse && mouseX && mouseY) { + horizontalOriginShift += e.clientX - mouseX; + verticalOriginShift += e.clientY - mouseY; pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); } - // Store current position mouseX = e.clientX; mouseY = e.clientY; }; - -// cmd + 0 or ctrl + 0 to restore zoom window.addEventListener('keydown', (e) => { - if (e.key == '0' && e.ctrlKey) { - resetScale(); + if (e.key == '0' && e.ctrlKey) { + resetScale(); return; - } + } - shoudFollowMouse = !!e.shiftKey; + shouldFollowMouse = !!e.shiftKey; + + // Zoom in with Numpad Plus + if (e.shiftKey && e.keyCode === 109) { + let x = window.innerWidth / 2; + let y = window.innerHeight / 2; + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let newScale = pageScale + deltaMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); + } + + // Zoom out with Numpad Minus + if (e.shiftKey && e.keyCode === 107) { + let x = window.innerWidth / 2; + let y = window.innerHeight / 2; + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let newScale = pageScale - deltaMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); + } }); window.addEventListener('keyup', (e) => { - shoudFollowMouse = !!e.shiftKey; + shouldFollowMouse = !!e.shiftKey; }); -// because scroll top/left are handled as integers only, we only read the translation from scroll once scroll has changed -// if we didn't, our translation would have ugly precision issues => setTranslationX(4.5) -> translationX = 4 let ignoredScrollLeft = null; let ignoredScrollTop = null; -function updateTranslationFromScroll(){ - if (getScrollBoxElement().scrollLeft !== ignoredScrollLeft) { - translationX = -getScrollBoxElement().scrollLeft; - ignoredScrollLeft = null; - } - if (getScrollBoxElement().scrollTop !== ignoredScrollTop) { - translationY = -getScrollBoxElement().scrollTop; - ignoredScrollTop = null; - } + +function updateTranslationFromScroll() { + if (getScrollBoxElement().scrollLeft !== ignoredScrollLeft) { + translationX = -getScrollBoxElement().scrollLeft; + ignoredScrollLeft = null; + } + if (getScrollBoxElement().scrollTop !== ignoredScrollTop) { + translationY = -getScrollBoxElement().scrollTop; + ignoredScrollTop = null; + } } -// https://github.com/rochal/jQuery-slimScroll/issues/316 + scrollEventElement.addEventListener(`scroll`, updateTranslationFromScroll, { capture: false, passive: false }); wheelEventElement.addEventListener(`wheel`, (e) => { - if (e.shiftKey && shiftKeyZoom) { - if (e.defaultPrevented) return; - - let x = e.clientX - getScrollBoxElement().offsetLeft; - let y = e.clientY - getScrollBoxElement().offsetTop; - // x in non-scrolling, non-transformed coordinates relative to the scrollBoxElement - // 0 is always the left side and is always the right side - - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; - - let newScale = pageScale + e.deltaY * deltaMultiplier; - let scaleBy = pageScale/newScale; - - applyScale(scaleBy, x, y, false); - - e.preventDefault(); - e.stopPropagation(); - } else { - // e.preventDefault(); - restoreControl(); - } + if (e.shiftKey && shiftKeyZoom) { + if (e.defaultPrevented) return; + let x = e.clientX - getScrollBoxElement().offsetLeft; + let y = e.clientY - getScrollBoxElement().offsetTop; + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let newScale = pageScale + e.deltaY * deltaMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); + } else { + restoreControl(); + } }, { capture: false, passive: false }); getScrollBoxElement().addEventListener(`mousemove`, restoreControl); getScrollBoxElement().addEventListener(`mousedown`, restoreControl); let controlDisabled = false; -function disableControl() { - if (controlDisabled) return; - - if (disableScrollbarsWhenZooming) { - let verticalScrollBarWidth = window.innerWidth - pageElement.clientWidth; - let horizontalScrollBarWidth = window.innerHeight - pageElement.clientHeight; - - // disable scrolling for performance - pageElement.style.setProperty('overflow', 'hidden', 'important'); - // since we're disabling a scrollbar we need to apply a margin to replicate the offset (if any) it introduced - // this prevent the page from being shifted about as the scrollbar is hidden and shown - pageElement.style.setProperty('margin-right', verticalScrollBarWidth + 'px', 'important'); - pageElement.style.setProperty('margin-bottom', horizontalScrollBarWidth + 'px', 'important'); - } +function disableControl() { + if (controlDisabled) return; + + if (disableScrollbarsWhenZooming) { + let verticalScrollBarWidth = window.innerWidth - pageElement.clientWidth; + let horizontalScrollBarWidth = window.innerHeight - pageElement.clientHeight; + pageElement.style.setProperty('overflow', 'hidden', 'important'); + pageElement.style.setProperty('margin-right', verticalScrollBarWidth + 'px', 'important'); + pageElement.style.setProperty('margin-bottom', horizontalScrollBarWidth + 'px', 'important'); + } - // document.body.style.pointerEvents = 'none'; - controlDisabled = true; + controlDisabled = true; } function restoreControl() { - if (!controlDisabled) return; - // scrolling must be enabled for panning - pageElement.style.overflow = 'auto'; - pageElement.style.marginRight = ''; - pageElement.style.marginBottom = ''; - // document.body.style.pointerEvents = ''; - controlDisabled = false; + if (!controlDisabled) return; + pageElement.style.overflow = 'auto'; + pageElement.style.marginRight = ''; + pageElement.style.marginBottom = ''; + controlDisabled = false; } let qualityTimeoutHandle = null; let overflowTimeoutHandle = null; function updateTransform(scaleModeOverride, shouldDisableControl) { - if (shouldDisableControl == null) { - shouldDisableControl = true; - } - - let sm = scaleModeOverride == null ? scaleMode : scaleModeOverride; - - if (sm === 0 || alwaysHighQuality) { - // scaleX/scaleY - pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); - } else { - // perspective (reduced quality but faster) - let p = 1; // what's the best value here? - let z = p - p/pageScale; - - pageElement.style.setProperty('transform', `perspective(${p}px) translateZ(${z}px)`, 'important'); - - // wait a short period before restoring the quality - // we use a timeout for trackpad because we can't detect when the user has finished the gesture on the hardware - // we can only detect gesture update events ('wheel' + ctrl) - window.clearTimeout(qualityTimeoutHandle); - qualityTimeoutHandle = setTimeout(function(){ - pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); - }, highQualityWait_ms); - } - - pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); - - // hack to restore normal behavior that's upset after applying the transform - pageElement.style.position = `relative`; - pageElement.style.height = `100%`; - - // when translation is positive, the offset is applied via left/top positioning - // negative translation is applied via scroll - if (minScale < 1) { - pageElement.style.setProperty('left', `${Math.max(translationX, 0) - overflowTranslationX}px`, 'important'); - pageElement.style.setProperty('top', `${Math.max(translationY, 0) - overflowTranslationY}px`, 'important'); - } - - // weird performance hack - is it batching the changes? - pageElement.style.transitionProperty = `transform, left, top`; - pageElement.style.transitionDuration = `0s`; - - if (shouldDisableControl) { - disableControl(); - clearTimeout(overflowTimeoutHandle); - overflowTimeoutHandle = setTimeout(function(){ - restoreControl(); - }, overflowTimeout_ms); - } + if (shouldDisableControl == null) { + shouldDisableControl = true; + } + + let sm = scaleModeOverride == null ? scaleMode : scaleModeOverride; + + if (sm === 0 || alwaysHighQuality) { + pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); + } else { + let p = 1; + let z = p - p / pageScale; + pageElement.style.setProperty('transform', `perspective(${p}px) translateZ(${z}px)`, 'important'); + window.clearTimeout(qualityTimeoutHandle); + qualityTimeoutHandle = setTimeout(function () { + pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); + }, highQualityWait_ms); + } + + pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); + pageElement.style.position = `relative`; + pageElement.style.height = `100%`; + pageElement.style.transitionProperty = `transform, left, top`; + pageElement.style.transitionDuration = `0s`; + + if (shouldDisableControl) { + disableControl(); + clearTimeout(overflowTimeoutHandle); + overflowTimeoutHandle = setTimeout(function () { + restoreControl(); + }, overflowTimeout_ms); + } } function applyScale(scaleBy, x_scrollBoxElement, y_scrollBoxElement) { - // x/y coordinates in untransformed coordinates relative to the scroll container - // if the container is the window, then the coordinates are relative to the window - // ignoring any scroll offset. The coordinates do not change as the page is transformed - - function getTranslationX(){ return translationX; } - function getTranslationY(){ return translationY; } - function setTranslationX(v) { - // clamp v to scroll range - // this limits minScale to 1 - v = Math.min(v, 0); - v = Math.max(v, -(getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth)); - - translationX = v; - - getScrollBoxElement().scrollLeft = Math.max(-v, 0); - ignoredScrollLeft = getScrollBoxElement().scrollLeft; - - // scroll-transform what we're unable to apply - // either there is no scroll-bar or we want to scroll past the end - overflowTranslationX = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth), 0) : 0; - } - function setTranslationY(v) { - // clamp v to scroll range - // this limits minScale to 1 - v = Math.min(v, 0); - v = Math.max(v, -(getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight)); - - translationY = v; - - getScrollBoxElement().scrollTop = Math.max(-v, 0); - ignoredScrollTop = getScrollBoxElement().scrollTop; - - overflowTranslationY = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight), 0) : 0; - } - - // resize pageElement - let pageScaleBefore = pageScale; - pageScale *= scaleBy; - pageScale = Math.min(Math.max(pageScale, minScale), maxScale); - let effectiveScale = pageScale/pageScaleBefore; - - if(pageScale === 1) { + function getTranslationX() { return translationX; } + function getTranslationY() { return translationY; } + function setTranslationX(v) { + v = Math.min(v, 0); + v = Math.max(v, -(getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth)); + translationX = v; + getScrollBoxElement().scrollLeft = Math.max(-v, 0); + ignoredScrollLeft = getScrollBoxElement().scrollLeft; + overflowTranslationX = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth), 0) : 0; + } + function setTranslationY(v) { + v = Math.min(v, 0); + v = Math.max(v, -(getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight)); + translationY = v; + getScrollBoxElement().scrollTop = Math.max(-v, 0); + ignoredScrollTop = getScrollBoxElement().scrollTop; + overflowTranslationY = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight), 0) : 0; + } + + let pageScaleBefore = pageScale; + pageScale *= scaleBy; + pageScale = Math.min(Math.max(pageScale, minScale), maxScale); + let effectiveScale = pageScale / pageScaleBefore; + + if (pageScale === 1) { canFollowMouse = false; } else { canFollowMouse = true; } - if(pageScale === 1 && (horizontalOriginShift || verticalOriginShift)) { + if (pageScale === 1 && (horizontalOriginShift || verticalOriginShift)) { horizontalOriginShift = 0; verticalOriginShift = 0; } - // when we hit min/max scale we can early exit - if (effectiveScale === 1) return; + if (effectiveScale === 1) return; - updateTransform(null, null); + updateTransform(null, null); - //zx and zy are the absolute coordinates of the mouse on the screen - let zx = x_scrollBoxElement; - let zy = y_scrollBoxElement; + let zx = x_scrollBoxElement; + let zy = y_scrollBoxElement; - // calculate new xy-translation - let tx = getTranslationX(); - tx = (tx - zx) * (effectiveScale) + zx; + let tx = getTranslationX(); + tx = (tx - zx) * (effectiveScale) + zx; - let ty = getTranslationY(); - ty = (ty - zy) * (effectiveScale) + zy; + let ty = getTranslationY(); + ty = (ty - zy) * (effectiveScale) + zy; - // apply new xy-translation - setTranslationX(tx); - setTranslationY(ty); + setTranslationX(tx); + setTranslationY(ty); - updateTransform(null, null); + updateTransform(null, null); } function resetScale() { - // reset state - pageScale = 1; - translationX = 0; - translationY = 0; - overflowTranslationX = 0; - overflowTranslationY = 0; + pageScale = 1; + translationX = 0; + translationY = 0; + overflowTranslationX = 0; + overflowTranslationY = 0; horizontalOriginShift = 0; verticalOriginShift = 0; - let scrollLeftBefore = getScrollBoxElement().scrollLeft; - let scrollLeftMaxBefore = getScrollBoxElement().scrollMax; - let scrollTopBefore = getScrollBoxElement().scrollTop; - let scrollTopMaxBefore = (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); - updateTransform(0, false, false); + let scrollLeftBefore = getScrollBoxElement().scrollLeft; + let scrollLeftMaxBefore = getScrollBoxElement().scrollMax; + let scrollTopBefore = getScrollBoxElement().scrollTop; + let scrollTopMaxBefore = (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); + updateTransform(0, false, false); - // restore scroll - getScrollBoxElement().scrollLeft = (scrollLeftBefore/scrollLeftMaxBefore) * (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth); - getScrollBoxElement().scrollTop = (scrollTopBefore/scrollTopMaxBefore) * (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); + getScrollBoxElement().scrollLeft = (scrollLeftBefore / scrollLeftMaxBefore) * (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth); + getScrollBoxElement().scrollTop = (scrollTopBefore / scrollTopMaxBefore) * (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); - updateTranslationFromScroll(); + updateTranslationFromScroll(); - // undo other css changes - pageElement.style.overflow = ''; - // document.body.style.pointerEvents = ''; + pageElement.style.overflow = ''; } From e6b1ac498f7e90dc8c9beb0da1200c677b8a71bc Mon Sep 17 00:00:00 2001 From: niraularohan Date: Fri, 26 Jan 2024 22:48:26 +0545 Subject: [PATCH 02/10] minor update --- extension/pinch-zoom.js | 55 ++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/extension/pinch-zoom.js b/extension/pinch-zoom.js index 5fb33a8..c799766 100644 --- a/extension/pinch-zoom.js +++ b/extension/pinch-zoom.js @@ -1,7 +1,8 @@ const scaleMode = 1; const minScale = 1.0; const maxScale = 10; -const zoomSpeedMultiplier = 0.03 / 5; +const touchpadZoomSpeedMultiplier = 0.03 / 5; // Touchpad zoom speed multiplier +const keyboardZoomSpeedMultiplier = 0.1; // Keyboard zoom speed multiplier const overflowTimeout_ms = 400; const highQualityWait_ms = 40; const alwaysHighQuality = false; @@ -53,30 +54,6 @@ window.addEventListener('keydown', (e) => { } shouldFollowMouse = !!e.shiftKey; - - // Zoom in with Numpad Plus - if (e.shiftKey && e.keyCode === 109) { - let x = window.innerWidth / 2; - let y = window.innerHeight / 2; - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; - let newScale = pageScale + deltaMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } - - // Zoom out with Numpad Minus - if (e.shiftKey && e.keyCode === 107) { - let x = window.innerWidth / 2; - let y = window.innerHeight / 2; - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; - let newScale = pageScale - deltaMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } }); window.addEventListener('keyup', (e) => { @@ -104,7 +81,7 @@ wheelEventElement.addEventListener(`wheel`, (e) => { if (e.defaultPrevented) return; let x = e.clientX - getScrollBoxElement().offsetLeft; let y = e.clientY - getScrollBoxElement().offsetTop; - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let deltaMultiplier = pinchZoomSpeed * touchpadZoomSpeedMultiplier; let newScale = pageScale + e.deltaY * deltaMultiplier; let scaleBy = pageScale / newScale; applyScale(scaleBy, x, y); @@ -256,3 +233,29 @@ function resetScale() { pageElement.style.overflow = ''; } + +window.addEventListener('keydown', (e) => { + if (e.shiftKey) { + // Zoom in with Numpad Plus + if (e.keyCode === 109) { + let x = window.innerWidth / 2; + let y = window.innerHeight / 2; + let newScale = pageScale + keyboardZoomSpeedMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); + } + + // Zoom out with Numpad Minus + if (e.keyCode === 107) { + let x = window.innerWidth / 2; + let y = window.innerHeight / 2; + let newScale = pageScale - keyboardZoomSpeedMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); + } + } +}); From d3c344d0e986d1f4e38b29adffd50bd851bf5890 Mon Sep 17 00:00:00 2001 From: niraularohan Date: Fri, 26 Jan 2024 22:52:52 +0545 Subject: [PATCH 03/10] rollback --- extension/pinch-zoom.js | 57 +++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/extension/pinch-zoom.js b/extension/pinch-zoom.js index c799766..e560d36 100644 --- a/extension/pinch-zoom.js +++ b/extension/pinch-zoom.js @@ -1,8 +1,7 @@ const scaleMode = 1; const minScale = 1.0; const maxScale = 10; -const touchpadZoomSpeedMultiplier = 0.03 / 5; // Touchpad zoom speed multiplier -const keyboardZoomSpeedMultiplier = 0.1; // Keyboard zoom speed multiplier +const zoomSpeedMultiplier = 0.03 / 5; const overflowTimeout_ms = 400; const highQualityWait_ms = 40; const alwaysHighQuality = false; @@ -13,7 +12,7 @@ let originMoveRate = 10; let shiftKeyZoom = true; let pinchZoomSpeed = 0.7; -let disableScrollbarsWhenZooming = false; +let disableScrollbarsWhenZooming = true; let pageScale = 1; let translationX = 0; @@ -54,6 +53,30 @@ window.addEventListener('keydown', (e) => { } shouldFollowMouse = !!e.shiftKey; + + // Zoom in with Numpad Plus + if (e.shiftKey && e.keyCode === 109) { + let x = window.innerWidth / 2; + let y = window.innerHeight / 2; + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let newScale = pageScale + deltaMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); + } + + // Zoom out with Numpad Minus + if (e.shiftKey && e.keyCode === 107) { + let x = window.innerWidth / 2; + let y = window.innerHeight / 2; + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let newScale = pageScale - deltaMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); + } }); window.addEventListener('keyup', (e) => { @@ -81,7 +104,7 @@ wheelEventElement.addEventListener(`wheel`, (e) => { if (e.defaultPrevented) return; let x = e.clientX - getScrollBoxElement().offsetLeft; let y = e.clientY - getScrollBoxElement().offsetTop; - let deltaMultiplier = pinchZoomSpeed * touchpadZoomSpeedMultiplier; + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; let newScale = pageScale + e.deltaY * deltaMultiplier; let scaleBy = pageScale / newScale; applyScale(scaleBy, x, y); @@ -233,29 +256,3 @@ function resetScale() { pageElement.style.overflow = ''; } - -window.addEventListener('keydown', (e) => { - if (e.shiftKey) { - // Zoom in with Numpad Plus - if (e.keyCode === 109) { - let x = window.innerWidth / 2; - let y = window.innerHeight / 2; - let newScale = pageScale + keyboardZoomSpeedMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } - - // Zoom out with Numpad Minus - if (e.keyCode === 107) { - let x = window.innerWidth / 2; - let y = window.innerHeight / 2; - let newScale = pageScale - keyboardZoomSpeedMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } - } -}); From 86e74c2e7502d9e6efa53eb76431a81d97334451 Mon Sep 17 00:00:00 2001 From: niraularohan Date: Fri, 26 Jan 2024 23:04:10 +0545 Subject: [PATCH 04/10] minor fix --- extension/pinch-zoom.js | 356 ++++++++++++++++++---------------------- 1 file changed, 163 insertions(+), 193 deletions(-) diff --git a/extension/pinch-zoom.js b/extension/pinch-zoom.js index e560d36..5b2bf59 100644 --- a/extension/pinch-zoom.js +++ b/extension/pinch-zoom.js @@ -1,4 +1,5 @@ -const scaleMode = 1; +// view scaling parameters and other options +const scaleMode = 1; // 0 = always high quality, 1 = low-quality while zooming const minScale = 1.0; const maxScale = 10; const zoomSpeedMultiplier = 0.03 / 5; @@ -6,20 +7,23 @@ const overflowTimeout_ms = 400; const highQualityWait_ms = 40; const alwaysHighQuality = false; -let horizontalOriginShift = 0; -let verticalOriginShift = 0; +let horizontalOriginShift = 0; // > 0 to the right, < 0 to the left +let verticalOriginShift = 0; // > 0 down, < 0 up let originMoveRate = 10; -let shiftKeyZoom = true; +// settings +let shiftKeyZoom = true; // enable zoom with shift + scroll by default let pinchZoomSpeed = 0.7; -let disableScrollbarsWhenZooming = true; +let disableScrollbarsWhenZooming = false; +// state let pageScale = 1; let translationX = 0; let translationY = 0; let overflowTranslationX = 0; let overflowTranslationY = 0; +// elements let pageElement = document.documentElement; let wheelEventElement = document.documentElement; let scrollEventElement = window; @@ -27,232 +31,198 @@ let scrollEventElement = window; const quirksMode = document.compatMode === 'BackCompat'; function getScrollBoxElement() { - return document.documentElement || document.body; + return document.documentElement || document.body; } +// apply user settings +chrome.storage.local.get([ + 'mtzoom_shiftkey', + 'mtzoom_speed', + 'mtzoom_disableScrollbarsWhenZooming', +], function (res) { + if (res.mtzoom_shiftkey != null) { + shiftKeyZoom = res.mtzoom_shiftkey; + } + if (res.mtzoom_speed != null) { + pinchZoomSpeed = res.mtzoom_speed; + } + if (res.mtzoom_disableScrollbarsWhenZooming != null) { + disableScrollbarsWhenZooming = res.mtzoom_disableScrollbarsWhenZooming; + } +}); + let mouseX, mouseY; let shouldFollowMouse = false; let canFollowMouse = false; document.onmousemove = (e) => { - if (!canFollowMouse) return; - if (shouldFollowMouse && mouseX && mouseY) { - horizontalOriginShift += e.clientX - mouseX; - verticalOriginShift += e.clientY - mouseY; - pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); - } - - mouseX = e.clientX; - mouseY = e.clientY; + mouseX = e.clientX; + mouseY = e.clientY; }; window.addEventListener('keydown', (e) => { - if (e.key == '0' && e.ctrlKey) { - resetScale(); - return; - } - - shouldFollowMouse = !!e.shiftKey; - - // Zoom in with Numpad Plus - if (e.shiftKey && e.keyCode === 109) { - let x = window.innerWidth / 2; - let y = window.innerHeight / 2; - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; - let newScale = pageScale + deltaMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } - - // Zoom out with Numpad Minus - if (e.shiftKey && e.keyCode === 107) { - let x = window.innerWidth / 2; - let y = window.innerHeight / 2; - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; - let newScale = pageScale - deltaMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } + if (e.shiftKey && e.keyCode === 107) { + // Handle zoom in + e.preventDefault(); + zoomIn(); + } else if (e.shiftKey && e.keyCode === 109) { + // Handle zoom out + e.preventDefault(); + zoomOut(); + } else { + shouldFollowMouse = !!e.shiftKey; + } }); window.addEventListener('keyup', (e) => { - shouldFollowMouse = !!e.shiftKey; + shouldFollowMouse = !!e.shiftKey; }); -let ignoredScrollLeft = null; -let ignoredScrollTop = null; - -function updateTranslationFromScroll() { - if (getScrollBoxElement().scrollLeft !== ignoredScrollLeft) { - translationX = -getScrollBoxElement().scrollLeft; - ignoredScrollLeft = null; - } - if (getScrollBoxElement().scrollTop !== ignoredScrollTop) { - translationY = -getScrollBoxElement().scrollTop; - ignoredScrollTop = null; - } -} +wheelEventElement.addEventListener('wheel', (e) => { + if (e.shiftKey && shiftKeyZoom) { + if (e.defaultPrevented) return; -scrollEventElement.addEventListener(`scroll`, updateTranslationFromScroll, { capture: false, passive: false }); + let x = e.clientX - getScrollBoxElement().offsetLeft; + let y = e.clientY - getScrollBoxElement().offsetTop; -wheelEventElement.addEventListener(`wheel`, (e) => { - if (e.shiftKey && shiftKeyZoom) { - if (e.defaultPrevented) return; - let x = e.clientX - getScrollBoxElement().offsetLeft; - let y = e.clientY - getScrollBoxElement().offsetTop; - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; - let newScale = pageScale + e.deltaY * deltaMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } else { - restoreControl(); - } + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + + let newScale = pageScale + e.deltaY * deltaMultiplier; + let scaleBy = pageScale / newScale; + + applyScale(scaleBy, x, y); + + e.preventDefault(); + e.stopPropagation(); + } else { + restoreControl(); + } }, { capture: false, passive: false }); -getScrollBoxElement().addEventListener(`mousemove`, restoreControl); -getScrollBoxElement().addEventListener(`mousedown`, restoreControl); +getScrollBoxElement().addEventListener('mousemove', restoreControl); +getScrollBoxElement().addEventListener('mousedown', restoreControl); let controlDisabled = false; - function disableControl() { - if (controlDisabled) return; + if (controlDisabled) return; + + if (disableScrollbarsWhenZooming) { + let verticalScrollBarWidth = window.innerWidth - pageElement.clientWidth; + let horizontalScrollBarWidth = window.innerHeight - pageElement.clientHeight; - if (disableScrollbarsWhenZooming) { - let verticalScrollBarWidth = window.innerWidth - pageElement.clientWidth; - let horizontalScrollBarWidth = window.innerHeight - pageElement.clientHeight; - pageElement.style.setProperty('overflow', 'hidden', 'important'); - pageElement.style.setProperty('margin-right', verticalScrollBarWidth + 'px', 'important'); - pageElement.style.setProperty('margin-bottom', horizontalScrollBarWidth + 'px', 'important'); - } + pageElement.style.setProperty('overflow', 'hidden', 'important'); + pageElement.style.setProperty('margin-right', verticalScrollBarWidth + 'px', 'important'); + pageElement.style.setProperty('margin-bottom', horizontalScrollBarWidth + 'px', 'important'); + } - controlDisabled = true; + controlDisabled = true; } function restoreControl() { - if (!controlDisabled) return; - pageElement.style.overflow = 'auto'; - pageElement.style.marginRight = ''; - pageElement.style.marginBottom = ''; - controlDisabled = false; + if (!controlDisabled) return; + + pageElement.style.overflow = 'auto'; + pageElement.style.marginRight = ''; + pageElement.style.marginBottom = ''; + controlDisabled = false; } let qualityTimeoutHandle = null; let overflowTimeoutHandle = null; function updateTransform(scaleModeOverride, shouldDisableControl) { - if (shouldDisableControl == null) { - shouldDisableControl = true; - } - - let sm = scaleModeOverride == null ? scaleMode : scaleModeOverride; - - if (sm === 0 || alwaysHighQuality) { - pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); - } else { - let p = 1; - let z = p - p / pageScale; - pageElement.style.setProperty('transform', `perspective(${p}px) translateZ(${z}px)`, 'important'); - window.clearTimeout(qualityTimeoutHandle); - qualityTimeoutHandle = setTimeout(function () { - pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); - }, highQualityWait_ms); - } - - pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); - pageElement.style.position = `relative`; - pageElement.style.height = `100%`; - pageElement.style.transitionProperty = `transform, left, top`; - pageElement.style.transitionDuration = `0s`; - - if (shouldDisableControl) { - disableControl(); - clearTimeout(overflowTimeoutHandle); - overflowTimeoutHandle = setTimeout(function () { - restoreControl(); - }, overflowTimeout_ms); - } -} + if (shouldDisableControl == null) { + shouldDisableControl = true; + } + + let sm = scaleModeOverride == null ? scaleMode : scaleModeOverride; -function applyScale(scaleBy, x_scrollBoxElement, y_scrollBoxElement) { - function getTranslationX() { return translationX; } - function getTranslationY() { return translationY; } - function setTranslationX(v) { - v = Math.min(v, 0); - v = Math.max(v, -(getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth)); - translationX = v; - getScrollBoxElement().scrollLeft = Math.max(-v, 0); - ignoredScrollLeft = getScrollBoxElement().scrollLeft; - overflowTranslationX = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth), 0) : 0; - } - function setTranslationY(v) { - v = Math.min(v, 0); - v = Math.max(v, -(getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight)); - translationY = v; - getScrollBoxElement().scrollTop = Math.max(-v, 0); - ignoredScrollTop = getScrollBoxElement().scrollTop; - overflowTranslationY = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight), 0) : 0; - } - - let pageScaleBefore = pageScale; - pageScale *= scaleBy; - pageScale = Math.min(Math.max(pageScale, minScale), maxScale); - let effectiveScale = pageScale / pageScaleBefore; - - if (pageScale === 1) { - canFollowMouse = false; - } else { - canFollowMouse = true; - } - - if (pageScale === 1 && (horizontalOriginShift || verticalOriginShift)) { - horizontalOriginShift = 0; - verticalOriginShift = 0; - } - - if (effectiveScale === 1) return; - - updateTransform(null, null); - - let zx = x_scrollBoxElement; - let zy = y_scrollBoxElement; - - let tx = getTranslationX(); - tx = (tx - zx) * (effectiveScale) + zx; - - let ty = getTranslationY(); - ty = (ty - zy) * (effectiveScale) + zy; - - setTranslationX(tx); - setTranslationY(ty); - - updateTransform(null, null); + if (sm === 0 || alwaysHighQuality) { + pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); + } else { + let p = 1; + let z = p - p / pageScale; + + pageElement.style.setProperty('transform', `perspective(${p}px) translateZ(${z}px)`, 'important'); + + window.clearTimeout(qualityTimeoutHandle); + qualityTimeoutHandle = setTimeout(function () { + pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); + }, highQualityWait_ms); + } + + // Calculate the relative position of the cursor within the viewport + let relativeX = mouseX - window.scrollX; + let relativeY = mouseY - window.scrollY; + + // Update the origin shift based on the cursor position + horizontalOriginShift = relativeX; + verticalOriginShift = relativeY; + + pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); + + pageElement.style.position = `relative`; + pageElement.style.height = `100%`; + + if (shouldDisableControl) { + disableControl(); + clearTimeout(overflowTimeoutHandle); + overflowTimeoutHandle = setTimeout(function () { + restoreControl(); + }, overflowTimeout_ms); + } } -function resetScale() { - pageScale = 1; - translationX = 0; - translationY = 0; - overflowTranslationX = 0; - overflowTranslationY = 0; - horizontalOriginShift = 0; - verticalOriginShift = 0; +function applyScale(scaleBy, x, y) { + let pageScaleBefore = pageScale; + pageScale *= scaleBy; + pageScale = Math.min(Math.max(pageScale, minScale), maxScale); + let effectiveScale = pageScale / pageScaleBefore; + + if (pageScale === 1) { + canFollowMouse = false; + } else { + canFollowMouse = true; + } + + if (pageScale === 1 && (horizontalOriginShift || verticalOriginShift)) { + horizontalOriginShift = 0; + verticalOriginShift = 0; + } + + if (effectiveScale === 1) return; + + updateTransform(null, null); + + let zx = x; + let zy = y; - let scrollLeftBefore = getScrollBoxElement().scrollLeft; - let scrollLeftMaxBefore = getScrollBoxElement().scrollMax; - let scrollTopBefore = getScrollBoxElement().scrollTop; - let scrollTopMaxBefore = (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); - updateTransform(0, false, false); + let tx = translationX; + tx = (tx - zx) * effectiveScale + zx; - getScrollBoxElement().scrollLeft = (scrollLeftBefore / scrollLeftMaxBefore) * (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth); - getScrollBoxElement().scrollTop = (scrollTopBefore / scrollTopMaxBefore) * (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); + let ty = translationY; + ty = (ty - zy) * effectiveScale + zy; - updateTranslationFromScroll(); + translationX = tx; + translationY = ty; - pageElement.style.overflow = ''; + updateTransform(null, null); +} + +function zoomIn() { + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let x = mouseX; + let y = mouseY; + let newScale = pageScale - deltaMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); +} + +function zoomOut() { + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let x = mouseX; + let y = mouseY; + let newScale = pageScale + deltaMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); } From 4810f10198a12614411f1e108c54cd6882fbc70c Mon Sep 17 00:00:00 2001 From: niraularohan Date: Fri, 26 Jan 2024 23:51:53 +0545 Subject: [PATCH 05/10] more better now --- extension/pinch-zoom.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/extension/pinch-zoom.js b/extension/pinch-zoom.js index 5b2bf59..d7421fe 100644 --- a/extension/pinch-zoom.js +++ b/extension/pinch-zoom.js @@ -6,6 +6,7 @@ const zoomSpeedMultiplier = 0.03 / 5; const overflowTimeout_ms = 400; const highQualityWait_ms = 40; const alwaysHighQuality = false; +const KeyboardZoomMultiplier = 100; let horizontalOriginShift = 0; // > 0 to the right, < 0 to the left let verticalOriginShift = 0; // > 0 down, < 0 up @@ -13,7 +14,7 @@ let originMoveRate = 10; // settings let shiftKeyZoom = true; // enable zoom with shift + scroll by default -let pinchZoomSpeed = 0.7; +let pinchZoomSpeed = 0.5; let disableScrollbarsWhenZooming = false; // state @@ -64,11 +65,11 @@ window.addEventListener('keydown', (e) => { if (e.shiftKey && e.keyCode === 107) { // Handle zoom in e.preventDefault(); - zoomIn(); + zoomIn(KeyboardZoomMultiplier); } else if (e.shiftKey && e.keyCode === 109) { // Handle zoom out e.preventDefault(); - zoomOut(); + zoomOut(KeyboardZoomMultiplier); } else { shouldFollowMouse = !!e.shiftKey; } @@ -209,8 +210,8 @@ function applyScale(scaleBy, x, y) { updateTransform(null, null); } -function zoomIn() { - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; +function zoomIn(speedMultiplier) { + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier * speedMultiplier; let x = mouseX; let y = mouseY; let newScale = pageScale - deltaMultiplier; @@ -218,8 +219,8 @@ function zoomIn() { applyScale(scaleBy, x, y); } -function zoomOut() { - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; +function zoomOut(speedMultiplier) { + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier * speedMultiplier; let x = mouseX; let y = mouseY; let newScale = pageScale + deltaMultiplier; From b7c8f667dece85fe7af2865d438e3fc12b3bbef8 Mon Sep 17 00:00:00 2001 From: niraularohan Date: Fri, 26 Jan 2024 23:58:11 +0545 Subject: [PATCH 06/10] rollbackkk --- extension/pinch-zoom.js | 356 ++++++++++++++++++++++------------------ 1 file changed, 194 insertions(+), 162 deletions(-) diff --git a/extension/pinch-zoom.js b/extension/pinch-zoom.js index d7421fe..f526005 100644 --- a/extension/pinch-zoom.js +++ b/extension/pinch-zoom.js @@ -1,30 +1,26 @@ -// view scaling parameters and other options -const scaleMode = 1; // 0 = always high quality, 1 = low-quality while zooming +const scaleMode = 1; const minScale = 1.0; const maxScale = 10; -const zoomSpeedMultiplier = 0.03 / 5; +const touchpadZoomSpeedMultiplier = 0.03 / 5; // Touchpad zoom speed multiplier +const keyboardZoomSpeedMultiplier = 0.1; // Keyboard zoom speed multiplier const overflowTimeout_ms = 400; const highQualityWait_ms = 40; const alwaysHighQuality = false; -const KeyboardZoomMultiplier = 100; -let horizontalOriginShift = 0; // > 0 to the right, < 0 to the left -let verticalOriginShift = 0; // > 0 down, < 0 up +let horizontalOriginShift = 0; +let verticalOriginShift = 0; let originMoveRate = 10; -// settings -let shiftKeyZoom = true; // enable zoom with shift + scroll by default -let pinchZoomSpeed = 0.5; +let shiftKeyZoom = true; +let pinchZoomSpeed = 0.7; let disableScrollbarsWhenZooming = false; -// state let pageScale = 1; let translationX = 0; let translationY = 0; let overflowTranslationX = 0; let overflowTranslationY = 0; -// elements let pageElement = document.documentElement; let wheelEventElement = document.documentElement; let scrollEventElement = window; @@ -32,198 +28,234 @@ let scrollEventElement = window; const quirksMode = document.compatMode === 'BackCompat'; function getScrollBoxElement() { - return document.documentElement || document.body; + return document.documentElement || document.body; } -// apply user settings -chrome.storage.local.get([ - 'mtzoom_shiftkey', - 'mtzoom_speed', - 'mtzoom_disableScrollbarsWhenZooming', -], function (res) { - if (res.mtzoom_shiftkey != null) { - shiftKeyZoom = res.mtzoom_shiftkey; - } - if (res.mtzoom_speed != null) { - pinchZoomSpeed = res.mtzoom_speed; - } - if (res.mtzoom_disableScrollbarsWhenZooming != null) { - disableScrollbarsWhenZooming = res.mtzoom_disableScrollbarsWhenZooming; - } -}); - let mouseX, mouseY; let shouldFollowMouse = false; let canFollowMouse = false; document.onmousemove = (e) => { - mouseX = e.clientX; - mouseY = e.clientY; + if (!canFollowMouse) return; + if (shouldFollowMouse && mouseX && mouseY) { + horizontalOriginShift += e.clientX - mouseX; + verticalOriginShift += e.clientY - mouseY; + pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); + } + + mouseX = e.clientX; + mouseY = e.clientY; }; window.addEventListener('keydown', (e) => { - if (e.shiftKey && e.keyCode === 107) { - // Handle zoom in - e.preventDefault(); - zoomIn(KeyboardZoomMultiplier); - } else if (e.shiftKey && e.keyCode === 109) { - // Handle zoom out - e.preventDefault(); - zoomOut(KeyboardZoomMultiplier); - } else { - shouldFollowMouse = !!e.shiftKey; - } + if (e.key == '0' && e.ctrlKey) { + resetScale(); + return; + } + + shouldFollowMouse = !!e.shiftKey; }); window.addEventListener('keyup', (e) => { - shouldFollowMouse = !!e.shiftKey; + shouldFollowMouse = !!e.shiftKey; }); -wheelEventElement.addEventListener('wheel', (e) => { - if (e.shiftKey && shiftKeyZoom) { - if (e.defaultPrevented) return; - - let x = e.clientX - getScrollBoxElement().offsetLeft; - let y = e.clientY - getScrollBoxElement().offsetTop; - - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; - - let newScale = pageScale + e.deltaY * deltaMultiplier; - let scaleBy = pageScale / newScale; +let ignoredScrollLeft = null; +let ignoredScrollTop = null; + +function updateTranslationFromScroll() { + if (getScrollBoxElement().scrollLeft !== ignoredScrollLeft) { + translationX = -getScrollBoxElement().scrollLeft; + ignoredScrollLeft = null; + } + if (getScrollBoxElement().scrollTop !== ignoredScrollTop) { + translationY = -getScrollBoxElement().scrollTop; + ignoredScrollTop = null; + } +} - applyScale(scaleBy, x, y); +scrollEventElement.addEventListener(`scroll`, updateTranslationFromScroll, { capture: false, passive: false }); - e.preventDefault(); - e.stopPropagation(); - } else { - restoreControl(); - } +wheelEventElement.addEventListener(`wheel`, (e) => { + if (e.shiftKey && shiftKeyZoom) { + if (e.defaultPrevented) return; + let x = e.clientX - getScrollBoxElement().offsetLeft; + let y = e.clientY - getScrollBoxElement().offsetTop; + let deltaMultiplier = pinchZoomSpeed * touchpadZoomSpeedMultiplier; + let newScale = pageScale + e.deltaY * deltaMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); + } else { + restoreControl(); + } }, { capture: false, passive: false }); -getScrollBoxElement().addEventListener('mousemove', restoreControl); -getScrollBoxElement().addEventListener('mousedown', restoreControl); +getScrollBoxElement().addEventListener(`mousemove`, restoreControl); +getScrollBoxElement().addEventListener(`mousedown`, restoreControl); let controlDisabled = false; -function disableControl() { - if (controlDisabled) return; - if (disableScrollbarsWhenZooming) { - let verticalScrollBarWidth = window.innerWidth - pageElement.clientWidth; - let horizontalScrollBarWidth = window.innerHeight - pageElement.clientHeight; +function disableControl() { + if (controlDisabled) return; - pageElement.style.setProperty('overflow', 'hidden', 'important'); - pageElement.style.setProperty('margin-right', verticalScrollBarWidth + 'px', 'important'); - pageElement.style.setProperty('margin-bottom', horizontalScrollBarWidth + 'px', 'important'); - } + if (disableScrollbarsWhenZooming) { + let verticalScrollBarWidth = window.innerWidth - pageElement.clientWidth; + let horizontalScrollBarWidth = window.innerHeight - pageElement.clientHeight; + pageElement.style.setProperty('overflow', 'hidden', 'important'); + pageElement.style.setProperty('margin-right', verticalScrollBarWidth + 'px', 'important'); + pageElement.style.setProperty('margin-bottom', horizontalScrollBarWidth + 'px', 'important'); + } - controlDisabled = true; + controlDisabled = true; } function restoreControl() { - if (!controlDisabled) return; - - pageElement.style.overflow = 'auto'; - pageElement.style.marginRight = ''; - pageElement.style.marginBottom = ''; - controlDisabled = false; + if (!controlDisabled) return; + pageElement.style.overflow = 'auto'; + pageElement.style.marginRight = ''; + pageElement.style.marginBottom = ''; + controlDisabled = false; } let qualityTimeoutHandle = null; let overflowTimeoutHandle = null; function updateTransform(scaleModeOverride, shouldDisableControl) { - if (shouldDisableControl == null) { - shouldDisableControl = true; - } - - let sm = scaleModeOverride == null ? scaleMode : scaleModeOverride; - - if (sm === 0 || alwaysHighQuality) { - pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); - } else { - let p = 1; - let z = p - p / pageScale; - - pageElement.style.setProperty('transform', `perspective(${p}px) translateZ(${z}px)`, 'important'); + if (shouldDisableControl == null) { + shouldDisableControl = true; + } + + let sm = scaleModeOverride == null ? scaleMode : scaleModeOverride; + + if (sm === 0 || alwaysHighQuality) { + pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); + } else { + let p = 1; + let z = p - p / pageScale; + pageElement.style.setProperty('transform', `perspective(${p}px) translateZ(${z}px)`, 'important'); + window.clearTimeout(qualityTimeoutHandle); + qualityTimeoutHandle = setTimeout(function () { + pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); + }, highQualityWait_ms); + } + + pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); + pageElement.style.position = `relative`; + pageElement.style.height = `100%`; + pageElement.style.transitionProperty = `transform, left, top`; + pageElement.style.transitionDuration = `0s`; + + if (shouldDisableControl) { + disableControl(); + clearTimeout(overflowTimeoutHandle); + overflowTimeoutHandle = setTimeout(function () { + restoreControl(); + }, overflowTimeout_ms); + } +} - window.clearTimeout(qualityTimeoutHandle); - qualityTimeoutHandle = setTimeout(function () { - pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); - }, highQualityWait_ms); - } +function applyScale(scaleBy, x_scrollBoxElement, y_scrollBoxElement) { + function getTranslationX() { return translationX; } + function getTranslationY() { return translationY; } + function setTranslationX(v) { + v = Math.min(v, 0); + v = Math.max(v, -(getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth)); + translationX = v; + getScrollBoxElement().scrollLeft = Math.max(-v, 0); + ignoredScrollLeft = getScrollBoxElement().scrollLeft; + overflowTranslationX = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth), 0) : 0; + } + function setTranslationY(v) { + v = Math.min(v, 0); + v = Math.max(v, -(getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight)); + translationY = v; + getScrollBoxElement().scrollTop = Math.max(-v, 0); + ignoredScrollTop = getScrollBoxElement().scrollTop; + overflowTranslationY = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight), 0) : 0; + } + + let pageScaleBefore = pageScale; + pageScale *= scaleBy; + pageScale = Math.min(Math.max(pageScale, minScale), maxScale); + let effectiveScale = pageScale / pageScaleBefore; + + if (pageScale === 1) { + canFollowMouse = false; + } else { + canFollowMouse = true; + } + + if (pageScale === 1 && (horizontalOriginShift || verticalOriginShift)) { + horizontalOriginShift = 0; + verticalOriginShift = 0; + } + + if (effectiveScale === 1) return; + + updateTransform(null, null); + + let zx = x_scrollBoxElement; + let zy = y_scrollBoxElement; + + let tx = getTranslationX(); + tx = (tx - zx) * (effectiveScale) + zx; + + let ty = getTranslationY(); + ty = (ty - zy) * (effectiveScale) + zy; + + setTranslationX(tx); + setTranslationY(ty); + + updateTransform(null, null); +} - // Calculate the relative position of the cursor within the viewport - let relativeX = mouseX - window.scrollX; - let relativeY = mouseY - window.scrollY; +function resetScale() { + pageScale = 1; + translationX = 0; + translationY = 0; + overflowTranslationX = 0; + overflowTranslationY = 0; + horizontalOriginShift = 0; + verticalOriginShift = 0; - // Update the origin shift based on the cursor position - horizontalOriginShift = relativeX; - verticalOriginShift = relativeY; + let scrollLeftBefore = getScrollBoxElement().scrollLeft; + let scrollLeftMaxBefore = getScrollBoxElement().scrollMax; + let scrollTopBefore = getScrollBoxElement().scrollTop; + let scrollTopMaxBefore = (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); + updateTransform(0, false, false); - pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); + getScrollBoxElement().scrollLeft = (scrollLeftBefore / scrollLeftMaxBefore) * (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth); + getScrollBoxElement().scrollTop = (scrollTopBefore / scrollTopMaxBefore) * (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); - pageElement.style.position = `relative`; - pageElement.style.height = `100%`; + updateTranslationFromScroll(); - if (shouldDisableControl) { - disableControl(); - clearTimeout(overflowTimeoutHandle); - overflowTimeoutHandle = setTimeout(function () { - restoreControl(); - }, overflowTimeout_ms); - } + pageElement.style.overflow = ''; } -function applyScale(scaleBy, x, y) { - let pageScaleBefore = pageScale; - pageScale *= scaleBy; - pageScale = Math.min(Math.max(pageScale, minScale), maxScale); - let effectiveScale = pageScale / pageScaleBefore; - - if (pageScale === 1) { - canFollowMouse = false; - } else { - canFollowMouse = true; +window.addEventListener('keydown', (e) => { + if (e.shiftKey) { + // Zoom in with Numpad Plus + if (e.keyCode === 109) { + let x = window.innerWidth / 2; + let y = window.innerHeight / 2; + let newScale = pageScale + keyboardZoomSpeedMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); } - if (pageScale === 1 && (horizontalOriginShift || verticalOriginShift)) { - horizontalOriginShift = 0; - verticalOriginShift = 0; + // Zoom out with Numpad Minus + if (e.keyCode === 107) { + let x = window.innerWidth / 2; + let y = window.innerHeight / 2; + let newScale = pageScale - keyboardZoomSpeedMultiplier; + let scaleBy = pageScale / newScale; + applyScale(scaleBy, x, y); + e.preventDefault(); + e.stopPropagation(); } - - if (effectiveScale === 1) return; - - updateTransform(null, null); - - let zx = x; - let zy = y; - - let tx = translationX; - tx = (tx - zx) * effectiveScale + zx; - - let ty = translationY; - ty = (ty - zy) * effectiveScale + zy; - - translationX = tx; - translationY = ty; - - updateTransform(null, null); -} - -function zoomIn(speedMultiplier) { - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier * speedMultiplier; - let x = mouseX; - let y = mouseY; - let newScale = pageScale - deltaMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); -} - -function zoomOut(speedMultiplier) { - let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier * speedMultiplier; - let x = mouseX; - let y = mouseY; - let newScale = pageScale + deltaMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); -} + } +}); \ No newline at end of file From 70e2f6b434672c8fcf880d33bc96d8bc76cc0c42 Mon Sep 17 00:00:00 2001 From: niraularohan Date: Sat, 27 Jan 2024 09:37:51 +0545 Subject: [PATCH 07/10] works as expected 1st draft --- extension/pinch-zoom.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/extension/pinch-zoom.js b/extension/pinch-zoom.js index f526005..9566e8d 100644 --- a/extension/pinch-zoom.js +++ b/extension/pinch-zoom.js @@ -37,14 +37,10 @@ let canFollowMouse = false; document.onmousemove = (e) => { if (!canFollowMouse) return; - if (shouldFollowMouse && mouseX && mouseY) { - horizontalOriginShift += e.clientX - mouseX; - verticalOriginShift += e.clientY - mouseY; - pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); + if (shouldFollowMouse) { + mouseX = e.clientX; + mouseY = e.clientY; } - - mouseX = e.clientX; - mouseY = e.clientY; }; window.addEventListener('keydown', (e) => { @@ -238,8 +234,8 @@ window.addEventListener('keydown', (e) => { if (e.shiftKey) { // Zoom in with Numpad Plus if (e.keyCode === 109) { - let x = window.innerWidth / 2; - let y = window.innerHeight / 2; + let x = mouseX != null ? mouseX : window.innerWidth / 2; + let y = mouseY != null ? mouseY : window.innerHeight / 2; let newScale = pageScale + keyboardZoomSpeedMultiplier; let scaleBy = pageScale / newScale; applyScale(scaleBy, x, y); @@ -249,8 +245,8 @@ window.addEventListener('keydown', (e) => { // Zoom out with Numpad Minus if (e.keyCode === 107) { - let x = window.innerWidth / 2; - let y = window.innerHeight / 2; + let x = mouseX != null ? mouseX : window.innerWidth / 2; + let y = mouseY != null ? mouseY : window.innerHeight / 2; let newScale = pageScale - keyboardZoomSpeedMultiplier; let scaleBy = pageScale / newScale; applyScale(scaleBy, x, y); @@ -258,4 +254,4 @@ window.addEventListener('keydown', (e) => { e.stopPropagation(); } } -}); \ No newline at end of file +}); From 6eba8d50fc6bfaeedf5723d5ad79edb6c4b71a54 Mon Sep 17 00:00:00 2001 From: niraularohan Date: Sat, 27 Jan 2024 10:13:14 +0545 Subject: [PATCH 08/10] Manifest v3 update --- extension/manifest.json | 42 +++++++--------- extension/pinch-zoom.js | 108 ++++++++++++++++++++++------------------ 2 files changed, 78 insertions(+), 72 deletions(-) diff --git a/extension/manifest.json b/extension/manifest.json index c38f2d2..ed2a2af 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,36 +1,32 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "Multi-touch Zoom", "version": "0.95", - // gecko stores browser specific things, no need for it using chrome - //"applications": { - // "gecko": { - // "id": "{90b5a72e-cdbd-49df-8304-5b5d6ea84a0f}", - // "strict_min_version": "57.0" - // } - //}, - "description": "Adds smooth multi-touch zoom that matches the behavior in Safari and Chrome", - - + "icons": { "48": "icons/icon-48.png", "96": "icons/icon-96.png", "192": "icons/icon-192.png" - }, - - "content_scripts": [{ + }, + + "content_scripts": [ + { "matches": [""], "js": ["pinch-zoom.js"], "run_at": "document_start" - }], - + } + ], + "permissions": [ - "storage", - "debugger" + "storage", + "activeTab" ], - - "options_ui": { - "page": "settings.html" - } -} + + "action": { + "default_popup": "settings.html" + }, + + "host_permissions": [""] + } + \ No newline at end of file diff --git a/extension/pinch-zoom.js b/extension/pinch-zoom.js index 9566e8d..15a5687 100644 --- a/extension/pinch-zoom.js +++ b/extension/pinch-zoom.js @@ -1,8 +1,7 @@ const scaleMode = 1; const minScale = 1.0; const maxScale = 10; -const touchpadZoomSpeedMultiplier = 0.03 / 5; // Touchpad zoom speed multiplier -const keyboardZoomSpeedMultiplier = 0.1; // Keyboard zoom speed multiplier +const zoomSpeedMultiplier = 0.03 / 5; const overflowTimeout_ms = 400; const highQualityWait_ms = 40; const alwaysHighQuality = false; @@ -31,16 +30,37 @@ function getScrollBoxElement() { return document.documentElement || document.body; } +chrome.storage.local.get([ + 'mtzoom_shiftkey', + 'mtzoom_speed', + 'mtzoom_disableScrollbarsWhenZooming', +], function (res) { + if (res.mtzoom_shiftkey != null) { + shiftKeyZoom = res.mtzoom_shiftkey; + } + if (res.mtzoom_speed != null) { + pinchZoomSpeed = res.mtzoom_speed; + } + if (res.mtzoom_disableScrollbarsWhenZooming != null) { + disableScrollbarsWhenZooming = res.mtzoom_disableScrollbarsWhenZooming; + } +}); + let mouseX, mouseY; -let shouldFollowMouse = false; +let shoudFollowMouse = false; let canFollowMouse = false; document.onmousemove = (e) => { if (!canFollowMouse) return; - if (shouldFollowMouse) { - mouseX = e.clientX; - mouseY = e.clientY; + if (shoudFollowMouse && mouseX && mouseY) { + horizontalOriginShift += e.clientX - mouseX; + verticalOriginShift += e.clientY - mouseY; + + pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); } + + mouseX = e.clientX; + mouseY = e.clientY; }; window.addEventListener('keydown', (e) => { @@ -49,17 +69,16 @@ window.addEventListener('keydown', (e) => { return; } - shouldFollowMouse = !!e.shiftKey; + shoudFollowMouse = !!e.shiftKey; }); window.addEventListener('keyup', (e) => { - shouldFollowMouse = !!e.shiftKey; + shoudFollowMouse = !!e.shiftKey; }); let ignoredScrollLeft = null; let ignoredScrollTop = null; - -function updateTranslationFromScroll() { +function updateTranslationFromScroll(){ if (getScrollBoxElement().scrollLeft !== ignoredScrollLeft) { translationX = -getScrollBoxElement().scrollLeft; ignoredScrollLeft = null; @@ -69,18 +88,22 @@ function updateTranslationFromScroll() { ignoredScrollTop = null; } } - scrollEventElement.addEventListener(`scroll`, updateTranslationFromScroll, { capture: false, passive: false }); wheelEventElement.addEventListener(`wheel`, (e) => { if (e.shiftKey && shiftKeyZoom) { if (e.defaultPrevented) return; + let x = e.clientX - getScrollBoxElement().offsetLeft; let y = e.clientY - getScrollBoxElement().offsetTop; - let deltaMultiplier = pinchZoomSpeed * touchpadZoomSpeedMultiplier; + + let deltaMultiplier = pinchZoomSpeed * zoomSpeedMultiplier; + let newScale = pageScale + e.deltaY * deltaMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); + let scaleBy = pageScale/newScale; + + applyScale(scaleBy, x, y, false); + e.preventDefault(); e.stopPropagation(); } else { @@ -92,14 +115,15 @@ getScrollBoxElement().addEventListener(`mousemove`, restoreControl); getScrollBoxElement().addEventListener(`mousedown`, restoreControl); let controlDisabled = false; - function disableControl() { if (controlDisabled) return; if (disableScrollbarsWhenZooming) { let verticalScrollBarWidth = window.innerWidth - pageElement.clientWidth; let horizontalScrollBarWidth = window.innerHeight - pageElement.clientHeight; + pageElement.style.setProperty('overflow', 'hidden', 'important'); + pageElement.style.setProperty('margin-right', verticalScrollBarWidth + 'px', 'important'); pageElement.style.setProperty('margin-bottom', horizontalScrollBarWidth + 'px', 'important'); } @@ -109,9 +133,11 @@ function disableControl() { function restoreControl() { if (!controlDisabled) return; + pageElement.style.overflow = 'auto'; pageElement.style.marginRight = ''; pageElement.style.marginBottom = ''; + controlDisabled = false; } @@ -129,53 +155,63 @@ function updateTransform(scaleModeOverride, shouldDisableControl) { pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); } else { let p = 1; - let z = p - p / pageScale; + let z = p - p/pageScale; + pageElement.style.setProperty('transform', `perspective(${p}px) translateZ(${z}px)`, 'important'); + window.clearTimeout(qualityTimeoutHandle); - qualityTimeoutHandle = setTimeout(function () { + qualityTimeoutHandle = setTimeout(function(){ pageElement.style.setProperty('transform', `scaleX(${pageScale}) scaleY(${pageScale})`, 'important'); }, highQualityWait_ms); } pageElement.style.setProperty('transform-origin', `${horizontalOriginShift}px ${verticalOriginShift}px`, 'important'); + pageElement.style.position = `relative`; pageElement.style.height = `100%`; + pageElement.style.transitionProperty = `transform, left, top`; pageElement.style.transitionDuration = `0s`; if (shouldDisableControl) { disableControl(); clearTimeout(overflowTimeoutHandle); - overflowTimeoutHandle = setTimeout(function () { + overflowTimeoutHandle = setTimeout(function(){ restoreControl(); }, overflowTimeout_ms); } } function applyScale(scaleBy, x_scrollBoxElement, y_scrollBoxElement) { - function getTranslationX() { return translationX; } - function getTranslationY() { return translationY; } + function getTranslationX(){ return translationX; } + function getTranslationY(){ return translationY; } function setTranslationX(v) { v = Math.min(v, 0); v = Math.max(v, -(getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth)); + translationX = v; + getScrollBoxElement().scrollLeft = Math.max(-v, 0); ignoredScrollLeft = getScrollBoxElement().scrollLeft; + overflowTranslationX = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth), 0) : 0; } function setTranslationY(v) { v = Math.min(v, 0); v = Math.max(v, -(getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight)); + translationY = v; + getScrollBoxElement().scrollTop = Math.max(-v, 0); ignoredScrollTop = getScrollBoxElement().scrollTop; + overflowTranslationY = v < 0 ? Math.max((-v) - (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight), 0) : 0; } let pageScaleBefore = pageScale; pageScale *= scaleBy; pageScale = Math.min(Math.max(pageScale, minScale), maxScale); - let effectiveScale = pageScale / pageScaleBefore; + let effectiveScale = pageScale/pageScaleBefore; if (pageScale === 1) { canFollowMouse = false; @@ -222,36 +258,10 @@ function resetScale() { let scrollTopMaxBefore = (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); updateTransform(0, false, false); - getScrollBoxElement().scrollLeft = (scrollLeftBefore / scrollLeftMaxBefore) * (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth); - getScrollBoxElement().scrollTop = (scrollTopBefore / scrollTopMaxBefore) * (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); + getScrollBoxElement().scrollLeft = (scrollLeftBefore/scrollLeftMaxBefore) * (getScrollBoxElement().scrollWidth - getScrollBoxElement().clientWidth); + getScrollBoxElement().scrollTop = (scrollTopBefore/scrollTopMaxBefore) * (getScrollBoxElement().scrollHeight - getScrollBoxElement().clientHeight); updateTranslationFromScroll(); pageElement.style.overflow = ''; } - -window.addEventListener('keydown', (e) => { - if (e.shiftKey) { - // Zoom in with Numpad Plus - if (e.keyCode === 109) { - let x = mouseX != null ? mouseX : window.innerWidth / 2; - let y = mouseY != null ? mouseY : window.innerHeight / 2; - let newScale = pageScale + keyboardZoomSpeedMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } - - // Zoom out with Numpad Minus - if (e.keyCode === 107) { - let x = mouseX != null ? mouseX : window.innerWidth / 2; - let y = mouseY != null ? mouseY : window.innerHeight / 2; - let newScale = pageScale - keyboardZoomSpeedMultiplier; - let scaleBy = pageScale / newScale; - applyScale(scaleBy, x, y); - e.preventDefault(); - e.stopPropagation(); - } - } -}); From 3a499fce7592af58d89e9a47f14de527c1750986 Mon Sep 17 00:00:00 2001 From: Rohan Niraula <59250480+niraularohan@users.noreply.github.com> Date: Sat, 27 Jan 2024 11:13:14 +0545 Subject: [PATCH 09/10] Update README.md --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b41033f..d7d46f8 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,12 @@ # About -This is a fork of: https://github.com/NayamAmarshe/firefox-multi-touch-zoom +This is a fork of: https://github.com/bmarwane/chrome-multi-touch-zoom -I added a simple way to support mouse movement when zoomed-in by pressing SHIFT key and moving the mouse. - -I do not plan to actively support this extension. +I just updated the extension to work with manifest v3 and v2 is going to be deprecated soon! # Installation -- clone this repo or [download the code](https://github.com/bmarwane/chrome-multi-touch-zoom/archive/refs/heads/master.zip) - +- clone this repo - Open the extensions page - Turn on Developer Mode - Press 'Load Unpacked' button. From 9b6b2f3b37e9fdc9d723284d048e351b9fc1ade1 Mon Sep 17 00:00:00 2001 From: Rohan Niraula <59250480+niraularohan@users.noreply.github.com> Date: Sat, 27 Jan 2024 13:35:34 +0545 Subject: [PATCH 10/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7d46f8..e5ee524 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This is a fork of: https://github.com/bmarwane/chrome-multi-touch-zoom -I just updated the extension to work with manifest v3 and v2 is going to be deprecated soon! +I just updated the extension to work with manifest v3 as v2 is going to be deprecated soon! # Installation