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

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: multitouch and tests 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 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.3;
114
115 // The font size is guaranteed to be in px.
116 var baseSize =
jdduke (slow) 2015/03/23 15:42:06 I assume this size will be reliably determined by
wychen 2015/03/24 22:52:08 It should be as of now. If things are added to the
117 parseFloat(getComputedStyle(document.documentElement).fontSize);
118
119 var refresh = function() {
jdduke (slow) 2015/03/23 15:42:06 Maybe |refreshTransform()|?
wychen 2015/03/24 22:52:08 Done.
120 var slowedScale = Math.exp(Math.log(scale) * FONT_SCALE_MULTIPLIER);
121 clampedScale = Math.max(0.4, Math.min(2.5, fontSizeAnchor * slowedScale));
122
123 // Use "fake" 3D transform so that the layer is not repainted.
124 // With 2D transform, the frame rate would be much lower.
125 document.body.style.transform =
126 'translate3d(' + shiftX + 'px,' +
127 shiftY + 'px, 0px)' +
128 'scale(' + clampedScale/fontSizeAnchor + ')';
129 };
130
131 function touchSpan(e) {
132 var count = e.touches.length;
133 var mid = touchClientMid(e);
134 var sum = 0;
135 for (var i = 0; i < count; i++) {
136 var dx = (e.touches[i].clientX - mid.x);
137 var dy = (e.touches[i].clientY - mid.y);
138 sum += Math.hypot(dx, dy);
139 }
140 return sum/count;
141 }
142
143 function touchClientMid(e) {
144 var count = e.touches.length;
145 var sumX = 0;
146 var sumY = 0;
147 for (var i = 0; i < count; i++) {
148 sumX += e.touches[i].clientX;
149 sumY += e.touches[i].clientY;
150 }
151 return {x: sumX/count, y: sumY/count};
152 }
153
154 function touchPageMid(e) {
155 var count = e.touches.length;
156 var sumX = 0;
157 var sumY = 0;
158 for (var i = 0; i < count; i++) {
159 sumX += e.touches[i].pageX;
160 sumY += e.touches[i].pageY;
161 }
162 return {x: sumX/count, y: sumY/count};
163 }
164
165 return {
166 handleTouchStart: function(e) {
167 if (e.touches.length < 2) return;
168 e.preventDefault();
169
170 var span = touchSpan(e);
171 var clientMid = touchClientMid(e);
172
173 if (e.touches.length > 2) {
174 lastSpan = span;
175 lastClientMid = clientMid;
176 refresh();
177 return;
178 }
179
180 scale = 1;
181 shiftX = 0;
182 shiftY = 0;
183
184 pinching = span > 0;
185 fontSizeAnchor =
186 parseFloat(getComputedStyle(document.documentElement).fontSize) /
187 baseSize;
188
189 var pinchOrigin = touchPageMid(e);
190 document.body.style.transformOrigin =
191 pinchOrigin.x + 'px ' + pinchOrigin.y + 'px';
192
193 // Try to preserve the pinching center after text reflow.
194 // This is accurate to the HTML element level.
195 focusElement = document.elementFromPoint(clientMid.x, clientMid.y);
196 var rect = focusElement.getBoundingClientRect();
197 initClientMid = clientMid;
198 focusPos = (initClientMid.y - rect.top) / (rect.bottom - rect.top);
199
200 lastSpan = span;
201 lastClientMid = clientMid;
202
203 refresh();
204 },
205
206 handleTouchMove: function(e) {
207 if (!pinching) return;
208 e.preventDefault();
jdduke (slow) 2015/03/23 15:42:06 It might be good to sanity check that we have >= 2
wychen 2015/03/24 22:52:08 Done.
209
210 var span = touchSpan(e);
211 var clientMid = touchClientMid(e);
212
213 scale *= touchSpan(e) / lastSpan;
214 shiftX += clientMid.x - lastClientMid.x;
215 shiftY += clientMid.y - lastClientMid.y;
216
217 refresh();
218
219 lastSpan = span;
220 lastClientMid = clientMid;
221 },
222
223 handleTouchEnd: function(e) {
224 if (!pinching) return;
225 e.preventDefault();
226
227 var span = touchSpan(e);
228 var clientMid = touchClientMid(e);
229
230 if (e.touches.length >= 2) {
231 lastSpan = span;
232 lastClientMid = clientMid;
233 refresh();
234 return;
235 }
236
237 pinching = false;
238
239 document.body.style.transformOrigin = '';
240 document.body.style.transform = '';
241 document.documentElement.style.fontSize = clampedScale * baseSize + "px";
242
243 var rect = focusElement.getBoundingClientRect();
244 var targetTop = focusPos * (rect.bottom - rect.top) + rect.top +
245 document.body.scrollTop - (initClientMid.y + shiftY);
246 document.body.scrollTop = targetTop;
247 },
248
249 handleTouchCancel: function(e) {
250 pinching = false;
jdduke (slow) 2015/03/23 15:42:06 We don't need to do any more cleanup here?
wychen 2015/03/24 22:52:08 Done.
251 },
252
253 reset: function() {
254 scale = 1;
255 shiftX = 0;
256 shiftY = 0;
257 clampedScale = 1;
258 document.documentElement.style.fontSize = clampedScale * baseSize + "px";
259 },
260
261 status: function() {
262 return {
263 scale: scale,
264 clampedScale: clampedScale,
265 shiftX: shiftX,
266 shiftY: shiftY
267 };
268 }
269 };
270 }());
271
272 window.addEventListener('touchstart', pincher.handleTouchStart, false);
273 window.addEventListener('touchmove', pincher.handleTouchMove, false);
274 window.addEventListener('touchend', pincher.handleTouchEnd, false);
275 window.addEventListener('touchcancel', pincher.handleTouchCancel, false);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698