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

Side by Side 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: address tdresser's comment Created 5 years, 8 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 function addToPage(html) { 5 function addToPage(html) {
6 var div = document.createElement('div'); 6 var div = document.createElement('div');
7 div.innerHTML = html; 7 div.innerHTML = html;
8 document.getElementById('content').appendChild(div); 8 document.getElementById('content').appendChild(div);
9 } 9 }
10 10
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 }(); 67 }();
68 68
69 // Add a listener to the "View Original" link to report opt-outs. 69 // Add a listener to the "View Original" link to report opt-outs.
70 document.getElementById('showOriginal').addEventListener('click', function(e) { 70 document.getElementById('showOriginal').addEventListener('click', function(e) {
71 var img = document.createElement('img'); 71 var img = document.createElement('img');
72 img.src = "/vieworiginal"; 72 img.src = "/vieworiginal";
73 img.style.display = "none"; 73 img.style.display = "none";
74 document.body.appendChild(img); 74 document.body.appendChild(img);
75 }, true); 75 }, true);
76 76
77 var pincher = (function() {
78 'use strict';
79 // When users pinch in Reader Mode, the page would zoom in or out as if it
80 // is a normal web page allowing user-zoom. At the end of pinch gesture, the
81 // page would do text reflow. These pinch-to-zoom and text reflow effects
82 // are not native, but are emulated using CSS and JavaScript.
83 //
84 // In order to achieve near-native zooming and panning frame rate, fake 3D
85 // transform is used so that the layer doesn't repaint for each frame.
86 //
87 // After the text reflow, the web content shown in viewport should roughly be
88 // the same paragraph before zooming.
89 //
90 // The control point of font size is the html element, so that both "em" and
91 // "rem" are adjusted.
92 //
93 // TODO(wychen): Improve scroll position when elementFromPoint is body.
94
95 var pinching = false;
96 var fontSizeAnchor = 1.0;
97
98 var focusElement = null;
99 var focusPos = 0;
100 var initClientMid;
101
102 var clampedScale = 1;
103
104 var lastSpan;
105 var lastClientMid;
106
107 var scale = 1;
108 var shiftX;
109 var shiftY;
110
111 // The zooming speed relative to pinching speed.
112 // @const
113 var FONT_SCALE_MULTIPLIER = 0.5;
114 var MIN_SPAN_LENGTH = 20;
115
116 // The font size is guaranteed to be in px.
117 var baseSize =
118 parseFloat(getComputedStyle(document.documentElement).fontSize);
119
120 var refreshTransform = function() {
121 var slowedScale = Math.exp(Math.log(scale) * FONT_SCALE_MULTIPLIER);
122 clampedScale = Math.max(0.4, Math.min(2.5, fontSizeAnchor * slowedScale));
123
124 // Use "fake" 3D transform so that the layer is not repainted.
125 // With 2D transform, the frame rate would be much lower.
126 document.body.style.transform =
127 'translate3d(' + shiftX + 'px,' +
128 shiftY + 'px, 0px)' +
129 'scale(' + clampedScale/fontSizeAnchor + ')';
130 };
131
132 function endPinch() {
133 pinching = false;
134
135 document.body.style.transformOrigin = '';
136 document.body.style.transform = '';
137 document.documentElement.style.fontSize = clampedScale * baseSize + "px";
138
139 var rect = focusElement.getBoundingClientRect();
140 var targetTop = focusPos * (rect.bottom - rect.top) + rect.top +
141 document.body.scrollTop - (initClientMid.y + shiftY);
142 document.body.scrollTop = targetTop;
143 }
144
145 function touchSpan(e) {
146 var count = e.touches.length;
147 var mid = touchClientMid(e);
148 var sum = 0;
149 for (var i = 0; i < count; i++) {
150 var dx = (e.touches[i].clientX - mid.x);
151 var dy = (e.touches[i].clientY - mid.y);
152 sum += Math.hypot(dx, dy);
153 }
154 // Avoid very small span.
155 return Math.max(MIN_SPAN_LENGTH, sum/count);
156 }
157
158 function touchClientMid(e) {
159 var count = e.touches.length;
160 var sumX = 0;
161 var sumY = 0;
162 for (var i = 0; i < count; i++) {
163 sumX += e.touches[i].clientX;
164 sumY += e.touches[i].clientY;
165 }
166 return {x: sumX/count, y: sumY/count};
167 }
168
169 function touchPageMid(e) {
170 var clientMid = touchClientMid(e);
171 return {x: clientMid.x - e.touches[0].clientX + e.touches[0].pageX,
172 y: clientMid.y - e.touches[0].clientY + e.touches[0].pageY};
173 }
174
175 return {
176 handleTouchStart: function(e) {
177 if (e.touches.length < 2) return;
178 e.preventDefault();
179
180 var span = touchSpan(e);
181 var clientMid = touchClientMid(e);
182
183 if (e.touches.length > 2) {
184 lastSpan = span;
185 lastClientMid = clientMid;
186 refreshTransform();
187 return;
188 }
189
190 scale = 1;
191 shiftX = 0;
192 shiftY = 0;
193
194 pinching = true;
195 fontSizeAnchor =
196 parseFloat(getComputedStyle(document.documentElement).fontSize) /
197 baseSize;
198
199 var pinchOrigin = touchPageMid(e);
200 document.body.style.transformOrigin =
201 pinchOrigin.x + 'px ' + pinchOrigin.y + 'px';
202
203 // Try to preserve the pinching center after text reflow.
204 // This is accurate to the HTML element level.
205 focusElement = document.elementFromPoint(clientMid.x, clientMid.y);
206 var rect = focusElement.getBoundingClientRect();
207 initClientMid = clientMid;
208 focusPos = (initClientMid.y - rect.top) / (rect.bottom - rect.top);
209
210 lastSpan = span;
211 lastClientMid = clientMid;
212
213 refreshTransform();
214 },
215
216 handleTouchMove: function(e) {
217 if (!pinching) return;
218 if (e.touches.length < 2) return;
219 e.preventDefault();
220
221 var span = touchSpan(e);
222 var clientMid = touchClientMid(e);
223
224 scale *= touchSpan(e) / lastSpan;
225 shiftX += clientMid.x - lastClientMid.x;
226 shiftY += clientMid.y - lastClientMid.y;
227
228 refreshTransform();
229
230 lastSpan = span;
231 lastClientMid = clientMid;
232 },
233
234 handleTouchEnd: function(e) {
235 if (!pinching) return;
236 e.preventDefault();
237
238 var span = touchSpan(e);
239 var clientMid = touchClientMid(e);
240
241 if (e.touches.length >= 2) {
242 lastSpan = span;
243 lastClientMid = clientMid;
244 refreshTransform();
245 return;
246 }
247
248 endPinch();
249 },
250
251 handleTouchCancel: function(e) {
252 endPinch();
253 },
254
255 reset: function() {
256 scale = 1;
257 shiftX = 0;
258 shiftY = 0;
259 clampedScale = 1;
260 document.documentElement.style.fontSize = clampedScale * baseSize + "px";
261 },
262
263 status: function() {
264 return {
265 scale: scale,
266 clampedScale: clampedScale,
267 shiftX: shiftX,
268 shiftY: shiftY
269 };
270 }
271 };
272 }());
273
274 window.addEventListener('touchstart', pincher.handleTouchStart, false);
275 window.addEventListener('touchmove', pincher.handleTouchMove, false);
276 window.addEventListener('touchend', pincher.handleTouchEnd, false);
277 window.addEventListener('touchcancel', pincher.handleTouchCancel, false);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698