Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(695)

Unified Diff: components/dom_distiller/core/javascript/dom_distiller_viewer.js

Issue 1009703002: Changing font size with pinch gesture in Reader Mode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/dom_distiller/core/css/distilledpage.css ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/dom_distiller/core/javascript/dom_distiller_viewer.js
diff --git a/components/dom_distiller/core/javascript/dom_distiller_viewer.js b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
index 55f53bbf3854feaebdf305bed92df2acce7a9ef2..551a8cbeee1748c2e62df347e62062e9069514af 100644
--- a/components/dom_distiller/core/javascript/dom_distiller_viewer.js
+++ b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
@@ -74,3 +74,123 @@ document.getElementById('showOriginal').addEventListener('click', function(e) {
document.body.appendChild(img);
}, true);
+window.addEventListener('load', function() {
+ // When users pinch in Reader Mode, the page would zoom in or out as if it
+ // is a normal web page allowing user-zoom. At the end of pinch gesture, the
+ // page would do text reflow. These pinch-to-zoom and text reflow effects
+ // are not native, but are emulated using CSS and JavaScript.
+ //
+ // In order to achieve near-native zooming and panning frame rate, fake 3D
+ // transform is used so that the layer doesn't repaint for each frame.
+ //
+ // After the text reflow, the web content shown in viewport should roughly be
+ // the same paragraph before zooming.
+ //
+ // The control point of font size is the html element, so that both "em" and
+ // "rem" are adjusted.
+ //
+ // TODO(wychen): Improve scroll position when elementFromPoint is body.
+
+ var pinching = false;
+ var pinchDistAnchor = 0;
+ var fontSizeAnchor = 1.0;
+ var focusElement = null;
+ var focusPos = 0;
+ var pinchOrigin = {x: 0, y: 0};
+ var scaleFactor = 1;
+ var lastClientMidY = 0;
+
+ // The zooming speed relative to pinching speed.
+ // @const
+ var FONT_SCALE_MULTIPLIER = 0.3;
+
+ // The font size is guaranteed to be in px.
+ var baseSize =
+ parseFloat(getComputedStyle(document.documentElement).fontSize);
+
+ var handleTouchStart = function(e) {
+ if (e.touches.length < 2) return;
+ e.preventDefault();
+ if (e.touches.length != 2) return;
jdduke (slow) 2015/03/16 20:27:52 How much more complicated is supporting >2 touches
wychen 2015/03/17 17:36:11 Good suggestion! I've never used more than two fin
+
+ pinchDistAnchor = touchDist(e);
+ pinching = pinchDistAnchor > 0;
+ fontSizeAnchor =
+ parseFloat(getComputedStyle(document.documentElement).fontSize)
+ / baseSize;
+
+ pinchOrigin = touchPageMid(e);
+ var clientMid = touchClientMid(e);
+ var pinchMidY = clientMid.y;
+ // Try to preserve the pinching center after text reflow.
+ // This is accurate to the HTML element level.
+ focusElement = document.elementFromPoint(clientMid.x, clientMid.y);
+ var rect = focusElement.getBoundingClientRect();
+ focusPos = (pinchMidY - rect.top) / (rect.bottom - rect.top);
+
+ lastClientMidY = clientMid.y;
+ };
+
+ var handleTouchMove = function(e) {
+ if (!pinching) return;
+ e.preventDefault();
+
+ var pinchScale = touchDist(e) / pinchDistAnchor;
+ var fontScale = 1 + ((pinchScale - 1) * FONT_SCALE_MULTIPLIER);
jdduke (slow) 2015/03/16 20:27:52 We might want to be more careful about the min fon
wychen 2015/03/17 17:36:11 0.4 might be in the unreadable range, and 0.4~2.5
+ scaleFactor = Math.max(0.4, Math.min(2.5, fontSizeAnchor * fontScale));
+ var mid = touchPageMid(e);
+
+ document.body.style.transformOrigin =
+ pinchOrigin.x + 'px ' + pinchOrigin.y + 'px';
+ // Use "fake" 3D transform so that the layer is not repainted.
+ // With 2D transform, the frame rate would be much lower.
jdduke (slow) 2015/03/16 20:27:53 I can't speak to this logic.
wychen 2015/03/17 17:36:12 The frame rate was enhanced from <30fps to 60fps t
+ document.body.style.transform =
+ 'translate3d(' + (mid.x - pinchOrigin.x) + 'px,' +
+ (mid.y - pinchOrigin.y) + 'px, 0px)' +
+ 'scale(' + scaleFactor/fontSizeAnchor + ')';
+
+ lastClientMidY = touchClientMid(e).y;
+ };
+
+ var handleTouchEnd = function(e) {
+ if (!pinching) return;
jdduke (slow) 2015/03/16 20:27:53 We'll need to be careful here as well, as we proba
wychen 2015/03/17 17:36:11 Indeed.
+ e.preventDefault();
+ pinching = false;
+
+ document.body.style.transformOrigin = '';
+ document.body.style.transform = '';
+ document.documentElement.style.fontSize = scaleFactor * baseSize + "px";
jdduke (slow) 2015/03/16 20:27:52 I'm an HTML newb so we'll want somebody else to re
wychen 2015/03/17 17:36:11 Why would this line in particular concern you? Th
jdduke (slow) 2015/03/17 17:49:51 Oh it's not that particular line that concerns me,
+
+ var rect = focusElement.getBoundingClientRect();
+ var targetTop = focusPos * (rect.bottom - rect.top) + rect.top +
+ document.body.scrollTop - lastClientMidY;
+ document.body.scrollTop = targetTop;
+ };
+
+ var handleTouchCancel = function(e) {
+ pinching = false;
+ };
+
+ function touchDist(e) {
+ var dx = (e.touches[0].screenX-e.touches[1].screenX);
+ var dy = (e.touches[0].screenY-e.touches[1].screenY);
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ function touchClientMid(e) {
+ var mx = (e.touches[0].clientX+e.touches[1].clientX)/2;
+ var my = (e.touches[0].clientY+e.touches[1].clientY)/2;
+ return {x: mx, y: my};
+ }
+
+ function touchPageMid(e) {
+ var mx = (e.touches[0].pageX+e.touches[1].pageX)/2;
+ var my = (e.touches[0].pageY+e.touches[1].pageY)/2;
+ return {x: mx, y: my};
+ }
+
+ window.addEventListener('touchstart', handleTouchStart, false);
+ window.addEventListener('touchmove', handleTouchMove, false);
+ window.addEventListener('touchend', handleTouchEnd, false);
+ window.addEventListener('touchcancel', handleTouchCancel, false);
+});
« no previous file with comments | « components/dom_distiller/core/css/distilledpage.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698