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

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 comments of jdduke 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) {
tdresser 2015/04/07 13:56:15 Would it be simpler to implement touchPageMid in t
wychen 2015/04/20 22:46:46 Done.
170 var count = e.touches.length;
171 var sumX = 0;
172 var sumY = 0;
173 for (var i = 0; i < count; i++) {
174 sumX += e.touches[i].pageX;
175 sumY += e.touches[i].pageY;
176 }
177 return {x: sumX/count, y: sumY/count};
178 }
179
180 return {
181 handleTouchStart: function(e) {
182 if (e.touches.length < 2) return;
183 e.preventDefault();
184
185 var span = touchSpan(e);
186 var clientMid = touchClientMid(e);
187
188 if (e.touches.length > 2) {
189 lastSpan = span;
190 lastClientMid = clientMid;
191 refreshTransform();
192 return;
193 }
194
195 scale = 1;
196 shiftX = 0;
197 shiftY = 0;
198
199 pinching = true;
200 fontSizeAnchor =
201 parseFloat(getComputedStyle(document.documentElement).fontSize) /
202 baseSize;
203
204 var pinchOrigin = touchPageMid(e);
205 document.body.style.transformOrigin =
206 pinchOrigin.x + 'px ' + pinchOrigin.y + 'px';
207
208 // Try to preserve the pinching center after text reflow.
209 // This is accurate to the HTML element level.
210 focusElement = document.elementFromPoint(clientMid.x, clientMid.y);
211 var rect = focusElement.getBoundingClientRect();
212 initClientMid = clientMid;
213 focusPos = (initClientMid.y - rect.top) / (rect.bottom - rect.top);
214
215 lastSpan = span;
216 lastClientMid = clientMid;
217
218 refreshTransform();
219 },
220
221 handleTouchMove: function(e) {
222 if (!pinching) return;
223 if (e.touches.length < 2) return;
224 e.preventDefault();
225
226 var span = touchSpan(e);
227 var clientMid = touchClientMid(e);
228
229 scale *= touchSpan(e) / lastSpan;
230 shiftX += clientMid.x - lastClientMid.x;
231 shiftY += clientMid.y - lastClientMid.y;
232
233 refreshTransform();
234
235 lastSpan = span;
236 lastClientMid = clientMid;
237 },
238
239 handleTouchEnd: function(e) {
240 if (!pinching) return;
241 e.preventDefault();
242
243 var span = touchSpan(e);
244 var clientMid = touchClientMid(e);
245
246 if (e.touches.length >= 2) {
247 lastSpan = span;
248 lastClientMid = clientMid;
249 refreshTransform();
250 return;
251 }
252
253 endPinch();
254 },
255
256 handleTouchCancel: function(e) {
257 endPinch();
258 },
259
260 reset: function() {
261 scale = 1;
262 shiftX = 0;
263 shiftY = 0;
264 clampedScale = 1;
265 document.documentElement.style.fontSize = clampedScale * baseSize + "px";
266 },
267
268 status: function() {
269 return {
270 scale: scale,
271 clampedScale: clampedScale,
272 shiftX: shiftX,
273 shiftY: shiftY
274 };
275 }
276 };
277 }());
278
279 window.addEventListener('touchstart', pincher.handleTouchStart, false);
280 window.addEventListener('touchmove', pincher.handleTouchMove, false);
281 window.addEventListener('touchend', pincher.handleTouchEnd, false);
282 window.addEventListener('touchcancel', pincher.handleTouchCancel, false);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698