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

Side by Side Diff: client/touch/Scroller.dart

Issue 8363040: Implement measurement using futures (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove duplicated imports from html.dart Created 9 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « client/touch/Scrollbar.dart ('k') | client/view/PagedViews.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * Implementation of a custom scrolling behavior. 6 * Implementation of a custom scrolling behavior.
7 * This behavior overrides native scrolling for an area. This area can be a 7 * This behavior overrides native scrolling for an area. This area can be a
8 * single defined part of a page, the entire page, or several different parts 8 * single defined part of a page, the entire page, or several different parts
9 * of a page. 9 * of a page.
10 * 10 *
(...skipping 12 matching lines...) Expand all
23 * positioning (setting the left and top styles). 23 * positioning (setting the left and top styles).
24 * 24 *
25 * For this to work properly you need to set -webkit-text-size-adjust to 'none' 25 * For this to work properly you need to set -webkit-text-size-adjust to 'none'
26 * on an ancestor element of the frame, or on the frame itself. If you forget 26 * on an ancestor element of the frame, or on the frame itself. If you forget
27 * this you may see the text content of the scrollable area changing size as it 27 * this you may see the text content of the scrollable area changing size as it
28 * moves. 28 * moves.
29 * 29 *
30 * The behavior is intended to support vertical and horizontal scrolling, and 30 * The behavior is intended to support vertical and horizontal scrolling, and
31 * scrolling with momentum when a touch gesture flicks with enough velocity. 31 * scrolling with momentum when a touch gesture flicks with enough velocity.
32 */ 32 */
33 typedef void Callback();
34
35 // Helper method to await the completion of 2 futures.
36 void joinFutures(List<Future> futures, Callback callback) {
37 int count = 0;
38 int len = futures.length;
39 void helper(value) {
40 count++;
41 if (count == len) {
42 callback();
43 }
44 }
45 for (Future p in futures) {
46 p.then(helper);
47 }
48 }
33 49
34 class Scroller implements Draggable, MomentumDelegate { 50 class Scroller implements Draggable, MomentumDelegate {
35 51
36 /** Pixels to move each time an arrow key is pressed. */ 52 /** Pixels to move each time an arrow key is pressed. */
37 static final ARROW_KEY_DELTA = 30; 53 static final ARROW_KEY_DELTA = 30;
38 static final SCROLL_WHEEL_VELOCITY = 0.01; 54 static final SCROLL_WHEEL_VELOCITY = 0.01;
39 static final FAST_SNAP_DECELERATION_FACTOR = 0.84; 55 static final FAST_SNAP_DECELERATION_FACTOR = 0.84;
40 static final PAGE_KEY_SCROLL_FRACTION = .85; 56 static final PAGE_KEY_SCROLL_FRACTION = .85;
41 57
42 // TODO(jacobr): remove this static variable. 58 // TODO(jacobr): remove this static variable.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 Function _setOffsetFunction; 121 Function _setOffsetFunction;
106 /** 122 /**
107 * Function that returns the content size that can be specified instead of 123 * Function that returns the content size that can be specified instead of
108 * querying the DOM. 124 * querying the DOM.
109 */ 125 */
110 Function _lookupContentSizeDelegate; 126 Function _lookupContentSizeDelegate;
111 127
112 Size _scrollSize; 128 Size _scrollSize;
113 Size _contentSize; 129 Size _contentSize;
114 Coordinate _minPoint; 130 Coordinate _minPoint;
115 bool _activeTransition = false;
116 bool _isStopping = false; 131 bool _isStopping = false;
117 Coordinate _contentStartOffset; 132 Coordinate _contentStartOffset;
118 bool _started = false; 133 bool _started = false;
119 bool _activeGesture = false; 134 bool _activeGesture = false;
120 ScrollWatcher _scrollWatcher; 135 ScrollWatcher _scrollWatcher;
121 136
122 Scroller(Element scrollableElem, [this.verticalEnabled = false, 137 Scroller(Element scrollableElem, [this.verticalEnabled = false,
123 this.horizontalEnabled = false, 138 this.horizontalEnabled = false,
124 this._momentumEnabled = true, 139 this._momentumEnabled = true,
125 this._lookupContentSizeDelegate = null, 140 this._lookupContentSizeDelegate = null,
126 num defaultDecelerationFactor = 1, 141 num defaultDecelerationFactor = 1,
127 int scrollTechnique = null, bool capture = false]) 142 int scrollTechnique = null, bool capture = false])
128 : _element = scrollableElem, 143 : _element = scrollableElem,
129 _frame = scrollableElem.parent, 144 _frame = scrollableElem.parent,
130 _scrollTechnique = scrollTechnique !== null 145 _scrollTechnique = scrollTechnique !== null
131 ? scrollTechnique : ScrollerScrollTechnique.TRANSFORM_3D, 146 ? scrollTechnique : ScrollerScrollTechnique.TRANSFORM_3D,
132 _minPoint = new Coordinate(0, 0), 147 _minPoint = new Coordinate(0, 0),
133 _maxPoint = new Coordinate(0, 0), 148 _maxPoint = new Coordinate(0, 0),
134 _maxOffset = new Coordinate(0, 0), 149 _maxOffset = new Coordinate(0, 0),
135 _minOffset = new Coordinate(0, 0), 150 _minOffset = new Coordinate(0, 0),
136 _contentOffset = new Coordinate(0, 0) { 151 _contentOffset = new Coordinate(0, 0) {
137 _touchHandler = new TouchHandler(this, scrollableElem.parent); 152 _touchHandler = new TouchHandler(this, scrollableElem.parent);
138 _momentum = new Momentum(this, defaultDecelerationFactor); 153 _momentum = new Momentum(this, defaultDecelerationFactor);
139 154
140 Element parentElem = scrollableElem.parent; 155 Element parentElem = scrollableElem.parent;
141 assert(parentElem != null); 156 assert(parentElem != null);
142 _setOffsetFunction = _getOffsetFunction(_scrollTechnique); 157 _setOffsetFunction = _getOffsetFunction(_scrollTechnique);
143 _element.on.transitionEnd.add((event) { onTransitionEnd(event); });
144 _touchHandler.setDraggable(this); 158 _touchHandler.setDraggable(this);
145 _touchHandler.enable(capture); 159 _touchHandler.enable(capture);
146 160
147 _frame.on.mouseWheel.add((e) { 161 _frame.on.mouseWheel.add((e) {
148 if (e.wheelDeltaY != 0 && verticalEnabled || 162 if (e.wheelDeltaY != 0 && verticalEnabled ||
149 e.wheelDeltaX != 0 && horizontalEnabled) { 163 e.wheelDeltaX != 0 && horizontalEnabled) {
150 num x = horizontalEnabled ? e.wheelDeltaX : 0; 164 num x = horizontalEnabled ? e.wheelDeltaX : 0;
151 num y = verticalEnabled ? e.wheelDeltaY : 0; 165 num y = verticalEnabled ? e.wheelDeltaY : 0;
152 if (throwDelta(x, y, FAST_SNAP_DECELERATION_FACTOR)) { 166 throwDelta(x, y, FAST_SNAP_DECELERATION_FACTOR);
153 e.preventDefault(); 167 e.preventDefault();
154 }
155 } 168 }
156 }); 169 });
157 170
158 _frame.on.keyDown.add((KeyboardEvent e) { 171 _frame.on.keyDown.add((KeyboardEvent e) {
159 bool handled = false; 172 bool handled = false;
160 // We ignore key events where further scrolling in that direction 173 // We ignore key events where further scrolling in that direction
161 // would have no impact which matches default browser behavior with 174 // would have no impact which matches default browser behavior with
162 // nested scrollable areas. 175 // nested scrollable areas.
163 176
164 switch(e.keyCode) { 177 switch(e.keyCode) {
165 case 33: // page-up 178 case 33: // page-up
166 handled = throwDelta( 179 throwDelta(
167 0, 180 0,
168 _scrollSize.height * PAGE_KEY_SCROLL_FRACTION); 181 _scrollSize.height * PAGE_KEY_SCROLL_FRACTION);
182 handled = true;
169 break; 183 break;
170 case 34: // page-down 184 case 34: // page-down
171 handled = throwDelta( 185 throwDelta(
172 0, -_scrollSize.height * PAGE_KEY_SCROLL_FRACTION); 186 0, -_scrollSize.height * PAGE_KEY_SCROLL_FRACTION);
187 handled = true;
173 break; 188 break;
174 case 35: // End 189 case 35: // End
175 handled = throwTo(_maxPoint.x, _minPoint.y, 190 throwTo(_maxPoint.x, _minPoint.y,
176 FAST_SNAP_DECELERATION_FACTOR); 191 FAST_SNAP_DECELERATION_FACTOR);
192 handled = true;
177 break; 193 break;
178 case 36: // Home 194 case 36: // Home
179 handled = throwTo(_maxPoint.x,_maxPoint.y, 195 throwTo(_maxPoint.x,_maxPoint.y,
180 FAST_SNAP_DECELERATION_FACTOR); 196 FAST_SNAP_DECELERATION_FACTOR);
197 handled = true;
181 break; 198 break;
182 /* TODO(jacobr): enable arrow keys when the don't conflict with other 199 /* TODO(jacobr): enable arrow keys when the don't conflict with other
183 application keyboard shortcuts. 200 application keyboard shortcuts.
184 case 38: // up 201 case 38: // up
185 handled = throwDelta( 202 handled = throwDelta(
186 0, 203 0,
187 ARROW_KEY_DELTA, 204 ARROW_KEY_DELTA,
188 FAST_SNAP_DECELERATION_FACTOR); 205 FAST_SNAP_DECELERATION_FACTOR);
189 break; 206 break;
190 case 40: // down 207 case 40: // down
(...skipping 12 matching lines...) Expand all
203 0, 220 0,
204 FAST_SNAP_DECELERATION_FACTOR); 221 FAST_SNAP_DECELERATION_FACTOR);
205 break; 222 break;
206 */ 223 */
207 } 224 }
208 if (handled) { 225 if (handled) {
209 e.preventDefault(); 226 e.preventDefault();
210 } 227 }
211 }); 228 });
212 // The scrollable element must be relatively positioned. 229 // The scrollable element must be relatively positioned.
213 assert(_scrollTechnique != ScrollerScrollTechnique.RELATIVE_POSITIONING || 230 // TODO(jacobr): this assert fires asynchronously which could be confusing.
214 window.getComputedStyle(_element, null).position != "static"); 231 if (_scrollTechnique == ScrollerScrollTechnique.RELATIVE_POSITIONING) {
232 _element.computedStyle.then((CSSStyleDeclaration style) {
233 assert(style.position != "static");
234 });
235 }
236
215 _initLayer(); 237 _initLayer();
216 } 238 }
217 239
218 EventListenerList get onScrollerStart() { 240 EventListenerList get onScrollerStart() {
219 if (_onScrollerStart === null) { 241 if (_onScrollerStart === null) {
220 _onScrollerStart = new SimpleEventListenerList(); 242 _onScrollerStart = new SimpleEventListenerList();
221 } 243 }
222 return _onScrollerStart; 244 return _onScrollerStart;
223 } 245 }
224 246
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 } 313 }
292 return end; 314 return end;
293 } 315 }
294 316
295 Coordinate get contentOffset() => _contentOffset; 317 Coordinate get contentOffset() => _contentOffset;
296 318
297 /** 319 /**
298 * Animate the position of the scroller to the specified [x], [y] coordinates 320 * Animate the position of the scroller to the specified [x], [y] coordinates
299 * by applying the throw gesture with the correct velocity to end at that 321 * by applying the throw gesture with the correct velocity to end at that
300 * location. 322 * location.
301 * Return false if no delta needs to be applied.
302 */ 323 */
303 bool throwTo(num x, num y, 324 void throwTo(num x, num y, [num decelerationFactor = null]) {
304 [num decelerationFactor = null]) { 325 reconfigure(() {
305 reconfigure(); 326 final snappedTarget = _snapToBounds(x, y);
306 final snappedTarget = _snapToBounds(x, y); 327 // If a deceleration factor is not specified, use the existing
307 // If a deceleration factor is not specified, use the existing 328 // deceleration factor specified by the momentum simulator.
308 // deceleration factor specified by the momentum simulator. 329 if (decelerationFactor == null) {
309 if (decelerationFactor == null) { 330 decelerationFactor = _momentum.decelerationFactor;
310 decelerationFactor = _momentum.decelerationFactor; 331 }
311 }
312 332
313 if (snappedTarget != currentTarget) { 333 if (snappedTarget != currentTarget) {
314 _momentum.abort(); 334 _momentum.abort();
315 reconfigure();
316 335
317 _startDeceleration( 336 _startDeceleration(
318 _momentum.calculateVelocity( 337 _momentum.calculateVelocity(
319 _contentOffset, 338 _contentOffset,
320 snappedTarget, 339 snappedTarget,
321 decelerationFactor), 340 decelerationFactor),
322 decelerationFactor); 341 decelerationFactor);
323 onDecelStart.dispatch(new Event(ScrollerEventType.DECEL_START)); 342 onDecelStart.dispatch(new Event(ScrollerEventType.DECEL_START));
324 return true; 343 }
325 } else { 344 });
326 return false;
327 }
328 } 345 }
329 346
330 bool throwDelta(num deltaX, num deltaY, [num decelerationFactor = null]) { 347 void throwDelta(num deltaX, num deltaY, [num decelerationFactor = null]) {
331 Coordinate start = _contentOffset; 348 Coordinate start = _contentOffset;
332 Coordinate end = currentTarget; 349 Coordinate end = currentTarget;
333 int x = end.x.toInt(); 350 int x = end.x.toInt();
334 int y = end.y.toInt(); 351 int y = end.y.toInt();
335 // If we are throwing in the opposite direction of the existing momentum, 352 // If we are throwing in the opposite direction of the existing momentum,
336 // cancel the current momentum. 353 // cancel the current momentum.
337 if (deltaX != 0 && deltaX.isNegative() != (end.x - start.x).isNegative()) { 354 if (deltaX != 0 && deltaX.isNegative() != (end.x - start.x).isNegative()) {
338 x = start.x; 355 x = start.x;
339 } 356 }
340 if (deltaY != 0 && deltaY.isNegative() != (end.y - start.y).isNegative()) { 357 if (deltaY != 0 && deltaY.isNegative() != (end.y - start.y).isNegative()) {
341 y = start.y; 358 y = start.y;
342 } 359 }
343 x += deltaX.toInt(); 360 x += deltaX.toInt();
344 y += deltaY.toInt(); 361 y += deltaY.toInt();
345 return throwTo(x, y, decelerationFactor); 362 throwTo(x, y, decelerationFactor);
346 }
347
348 void animateTo(num x, num y, [num duration = null,
349 String timingFunction = null]) {
350 if (duration !== null && duration != 0
351 && _scrollTechnique == ScrollerScrollTechnique.TRANSFORM_3D) {
352 _setWebkitTransition(_element, duration, StyleUtil.TRANSFORM_STYLE,
353 timingFunction);
354 }
355 _setContentOffset(x, y);
356 } 363 }
357 364
358 void setPosition(num x, num y) { 365 void setPosition(num x, num y) {
359 _momentum.abort(); 366 _momentum.abort();
360 _contentOffset.x = x; 367 _contentOffset.x = x;
361 _contentOffset.y = y; 368 _contentOffset.y = y;
362 _snapContentOffsetToBounds(); 369 _snapContentOffsetToBounds();
363 _setContentOffset(_contentOffset.x, _contentOffset.y); 370 _setContentOffset(_contentOffset.x, _contentOffset.y);
364 } 371 }
365 /** 372 /**
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 * Initialize the dom elements necessary for the scrolling to work. 418 * Initialize the dom elements necessary for the scrolling to work.
412 */ 419 */
413 void _initLayer() { 420 void _initLayer() {
414 // The scrollable node provided to Scroller must be a direct child 421 // The scrollable node provided to Scroller must be a direct child
415 // of the scrollable frame. 422 // of the scrollable frame.
416 // TODO(jacobr): Figure out why this is failing on dartium. 423 // TODO(jacobr): Figure out why this is failing on dartium.
417 // assert(_element.parent == _frame); 424 // assert(_element.parent == _frame);
418 _setContentOffset(_maxPoint.x, _maxPoint.y); 425 _setContentOffset(_maxPoint.x, _maxPoint.y);
419 } 426 }
420 427
421 void onDecelerate(num x, num y, [num duration = 0, 428 void onDecelerate(num x, num y) {
422 String timingFunction = null]) { 429 _setContentOffset(x, y);
423 // TODO(jacobr): remove once dartc fixes default args.
424 if (duration === null) {
425 duration = 0;
426 }
427 animateTo(x, y, duration, timingFunction);
428 } 430 }
429 431
430 void onDecelerationEnd() { 432 void onDecelerationEnd() {
431 _setWebkitTransition(_element, 0);
432 onScrollerEnd.dispatch(new Event(ScrollerEventType.SCROLLER_END)); 433 onScrollerEnd.dispatch(new Event(ScrollerEventType.SCROLLER_END));
433 _started = false; 434 _started = false;
434 } 435 }
435 436
436 void onDragEnd() { 437 void onDragEnd() {
437 _dragInProgress = false; 438 _dragInProgress = false;
438 439
439 bool decelerating = false; 440 bool decelerating = false;
440 if (_activeGesture) { 441 if (_activeGesture) {
441 if (_momentumEnabled && !_activeTransition) { 442 if (_momentumEnabled) {
442 decelerating = _startDeceleration(_touchHandler.getEndVelocity()); 443 decelerating = _startDeceleration(_touchHandler.getEndVelocity());
443 } 444 }
444 } 445 }
445 446
446 onScrollerDragEnd.dispatch(new Event(ScrollerEventType.DRAG_END)); 447 onScrollerDragEnd.dispatch(new Event(ScrollerEventType.DRAG_END));
447 448
448 if (!decelerating) { 449 if (!decelerating) {
449 _snapContentOffsetToBounds(); 450 _snapContentOffsetToBounds();
450 onScrollerEnd.dispatch(new Event(ScrollerEventType.SCROLLER_END)); 451 onScrollerEnd.dispatch(new Event(ScrollerEventType.SCROLLER_END));
451 _started = false; 452 _started = false;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 return !!(shouldVertical || shouldHorizontal && !verticalish); 491 return !!(shouldVertical || shouldHorizontal && !verticalish);
491 } 492 }
492 493
493 void onTouchEnd() { 494 void onTouchEnd() {
494 } 495 }
495 496
496 /** 497 /**
497 * Prepare the scrollable area for possible movement. 498 * Prepare the scrollable area for possible movement.
498 */ 499 */
499 bool onTouchStart(TouchEvent e) { 500 bool onTouchStart(TouchEvent e) {
500 reconfigure(); 501 reconfigure(() {
501 final touch = e.touches[0]; 502 final touch = e.touches[0];
502 if (_momentum.decelerating) { 503 if (_momentum.decelerating) {
503 e.preventDefault(); 504 e.preventDefault();
504 e.stopPropagation(); 505 e.stopPropagation();
505 stop(); 506 stop();
506 } else { 507 }
507 _setWebkitTransition(_element, 0); 508 _contentStartOffset = _contentOffset.clone();
508 } 509 _snapContentOffsetToBounds();
509 _contentStartOffset = _contentOffset.clone(); 510 });
510 _snapContentOffsetToBounds();
511 return true; 511 return true;
512 } 512 }
513 513
514 /** 514 /**
515 * Transition end event handler.
516 */
517 void onTransitionEnd(Event e) {
518 if (e.target == _element) {
519 _activeTransition = false;
520 _momentum.onTransitionEnd();
521 }
522 }
523
524 /**
525 * Recalculate dimensions of the frame and the content. Adjust the minPoint 515 * Recalculate dimensions of the frame and the content. Adjust the minPoint
526 * and maxPoint allowed for scrolling and scroll to a valid position. Call 516 * and maxPoint allowed for scrolling and scroll to a valid position. Call
527 * this method if you know the frame or content has been updated. Called 517 * this method if you know the frame or content has been updated. Called
528 * internally on every touchstart event the frame receives. 518 * internally on every touchstart event the frame receives.
529 */ 519 */
530 void reconfigure() { 520 void reconfigure(Callback callback) {
531 _resize(); 521 _resize(() {
532 _snapContentOffsetToBounds(); 522 _snapContentOffsetToBounds();
523 callback();
524 });
533 } 525 }
534 526
535 void reset() { 527 void reset() {
536 stop(); 528 stop();
537 _touchHandler.reset(); 529 _touchHandler.reset();
538 _setWebkitTransition(_element, 0); 530 _maxOffset.x = 0;
539 setMinOffset(0, 0); 531 _maxOffset.y = 0;
540 setMaxOffset(0, 0); 532 _minOffset.x = 0;
541 reconfigure(); 533 _minOffset.y = 0;
542 _setContentOffset(_maxPoint.x, _maxPoint.y); 534 reconfigure(() => _setContentOffset(_maxPoint.x, _maxPoint.y));
543 } 535 }
544 536
545 /** 537 /**
546 * Recalculate dimensions of the frame and the content. Adjust the minPoint 538 * Recalculate dimensions of the frame and the content. Adjust the minPoint
547 * and maxPoint allowed for scrolling. 539 * and maxPoint allowed for scrolling.
548 */ 540 */
549 void _resize() { 541 void _resize(Callback callback) {
550 _scrollSize = new Size(_frame.offsetWidth, _frame.offsetHeight); 542 final frameRect = _frame.rect;
551 _contentSize = _lookupContentSizeDelegate !== null ? 543 Future contentSizeFuture;
552 _lookupContentSizeDelegate() : 544
553 new Size(_element.scrollWidth, _element.scrollHeight); 545 if (_lookupContentSizeDelegate !== null) {
554 Size adjusted = _getAdjustedContentSize(); 546 contentSizeFuture = _lookupContentSizeDelegate();
555 _maxPoint = new Coordinate(-_maxOffset.x, -_maxOffset.y); 547 contentSizeFuture.then((Size size) {
556 _minPoint = new Coordinate( 548 _contentSize = size;
557 Math.min( 549 });
558 _scrollSize.width - adjusted.width + _minOffset.x, _maxPoint.x), 550 } else {
559 Math.min( 551 contentSizeFuture = _element.rect;
560 _scrollSize.height - adjusted.height + _minOffset.y, _maxPoint.y)); 552 contentSizeFuture.then((ElementRect rect) {
553 _contentSize = new Size(rect.scroll.width, rect.scroll.height);
554 });
555 }
556
557 joinFutures(<Future>[frameRect, contentSizeFuture], () {
558 _scrollSize = new Size(frameRect.value.offset.width,
559 frameRect.value.offset.height);
560 Size adjusted = _getAdjustedContentSize();
561 _maxPoint = new Coordinate(-_maxOffset.x, -_maxOffset.y);
562 _minPoint = new Coordinate(
563 Math.min(
564 _scrollSize.width - adjusted.width + _minOffset.x, _maxPoint.x),
565 Math.min(
566 _scrollSize.height - adjusted.height + _minOffset.y, _maxPoint.y)) ;
567 callback();
568 });
561 } 569 }
562 570
563 Coordinate _snapToBounds(num x, num y) { 571 Coordinate _snapToBounds(num x, num y) {
564 num clampX = GoogleMath.clamp(_minPoint.x, x, _maxPoint.x); 572 num clampX = GoogleMath.clamp(_minPoint.x, x, _maxPoint.x);
565 num clampY = GoogleMath.clamp(_minPoint.y, y, _maxPoint.y); 573 num clampY = GoogleMath.clamp(_minPoint.y, y, _maxPoint.y);
566 return new Coordinate(clampX, clampY); 574 return new Coordinate(clampX, clampY);
567 } 575 }
568 576
569 /** 577 /**
570 * Translate the content to a new position specified in px. 578 * Translate the content to a new position specified in px.
571 */ 579 */
572 void _setContentOffset(num x, num y) { 580 void _setContentOffset(num x, num y) {
573 _contentOffset.x = x; 581 _contentOffset.x = x;
574 _contentOffset.y = y; 582 _contentOffset.y = y;
575 _setOffsetFunction(_element, x, y); 583 _setOffsetFunction(_element, x, y);
576 onContentMoved.dispatch(new Event(ScrollerEventType.CONTENT_MOVED)); 584 onContentMoved.dispatch(new Event(ScrollerEventType.CONTENT_MOVED));
577 } 585 }
578 586
579 /** 587 /**
580 * Sets the offset to subtract from the maximum coordinate that the left upper
581 * corner of the content can scroll to.
582 */
583 void setMaxOffset(num x, num y) {
584 _maxOffset.x = x;
585 _maxOffset.y = y;
586 _resize();
587 }
588
589 /**
590 * Sets the offset to add to the minimum coordinate that the left upper corner
591 * of the content can scroll to.
592 */
593 void setMinOffset(num x, num y) {
594 _minOffset.x = x;
595 _minOffset.y = y;
596 _resize();
597 }
598
599 /**
600 * Enable or disable momentum. 588 * Enable or disable momentum.
601 */ 589 */
602 void setMomentum(bool enable) { 590 void setMomentum(bool enable) {
603 _momentumEnabled = enable; 591 _momentumEnabled = enable;
604 } 592 }
605 593
606 /** 594 /**
607 * Update the scroll technique used for animating the scrollable area.
608 */
609 void setScrollTechnique(int technique) {
610 _scrollTechnique = technique;
611 _setOffsetFunction = _getOffsetFunction(technique);
612
613 // The scrollable element must be relatively positioned.
614 assert(technique != ScrollerScrollTechnique.RELATIVE_POSITIONING ||
615 window.getComputedStyle(_element, null).position != "static");
616
617 if (technique != ScrollerScrollTechnique.TRANSFORM_3D) {
618 FxUtil.clearWebkitTransition(_element);
619 FxUtil.clearWebkitTransform(_element);
620 }
621 if (technique != ScrollerScrollTechnique.RELATIVE_POSITIONING) {
622 FxUtil.setLeftAndTop(_element, 0, 0);
623 }
624 _setOffsetFunction(_element, _contentOffset.x, _contentOffset.y);
625 }
626
627 /**
628 * Sets the vertical scrolled offset of the element where [y] is the amount 595 * Sets the vertical scrolled offset of the element where [y] is the amount
629 * of vertical space to be scrolled, in pixels. 596 * of vertical space to be scrolled, in pixels.
630 */ 597 */
631 void setVerticalOffset(num y) { 598 void setVerticalOffset(num y) {
632 _setContentOffset(_contentOffset.x, y); 599 _setContentOffset(_contentOffset.x, y);
633 } 600 }
634 601
635 /** 602 /**
636 * Applies a webkit transition on the element where the [duration] of the
637 * animation is specified in ms.
638 */
639 void _setWebkitTransition(Element el, num duration, [String property = null,
640 String timingFunction = null]) {
641 _activeTransition = duration > 0;
642 FxUtil.setWebkitTransition(el, duration, property, timingFunction);
643 }
644
645 /**
646 * Whether the scrollable area should scroll horizontally. Only 603 * Whether the scrollable area should scroll horizontally. Only
647 * returns true if the client has enabled horizontal scrolling, and the 604 * returns true if the client has enabled horizontal scrolling, and the
648 * content is wider than the frame. 605 * content is wider than the frame.
649 */ 606 */
650 bool _shouldScrollHorizontally() { 607 bool _shouldScrollHorizontally() {
651 return horizontalEnabled && _scrollSize.width < _contentSize.width; 608 return horizontalEnabled && _scrollSize.width < _contentSize.width;
652 } 609 }
653 610
654 /** 611 /**
655 * Whether the scrollable area should scroll vertically. Only 612 * Whether the scrollable area should scroll vertically. Only
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 if (!_shouldScrollVertically()) { 646 if (!_shouldScrollVertically()) {
690 velocity.y = 0; 647 velocity.y = 0;
691 } 648 }
692 assert(_minPoint != null); // Min point is not set 649 assert(_minPoint != null); // Min point is not set
693 assert(_maxPoint != null); // Max point is not set 650 assert(_maxPoint != null); // Max point is not set
694 return _momentum.start(velocity, _minPoint, _maxPoint, _contentOffset, 651 return _momentum.start(velocity, _minPoint, _maxPoint, _contentOffset,
695 decelerationFactor); 652 decelerationFactor);
696 } 653 }
697 654
698 Coordinate stop() { 655 Coordinate stop() {
699 Coordinate velocity = _momentum.stop(); 656 return _momentum.stop();
700
701 if (_momentum.decelerating) {
702 CSSMatrix transform1 = StyleUtil.getCurrentTransformMatrix(
703 _element);
704 if (!_activeTransition) {
705 _stopDecelerating(transform1.m41, transform1.m42);
706 return velocity;
707 }
708 _contentOffset.x = transform1.m41;
709 _contentOffset.y = transform1.m42;
710 _isStopping = true;
711 window.setTimeout(() {
712 CSSMatrix transform2 = StyleUtil.getCurrentTransformMatrix(
713 _element);
714 _setWebkitTransition(_element, 0);
715 window.setTimeout(function() { _isStopping = false; }, 0);
716 num deltaX = transform2.m41 - transform1.m41;
717 num deltaY = transform2.m42 - transform1.m42;
718 num newX = transform2.m41 + 2 * deltaX;
719 num newY = transform2.m42 + 2 * deltaY;
720 newX = GoogleMath.clamp(newX, _minPoint.x, _maxPoint.x);
721 newY = GoogleMath.clamp(newY, _minPoint.y, _maxPoint.y);
722 _stopDecelerating(newX, newY);
723 }, 0);
724 }
725 return velocity;
726 } 657 }
727 658
728 /** 659 /**
729 * Stop the deceleration of the scrollable content given a new position in px. 660 * Stop the deceleration of the scrollable content given a new position in px.
730 */ 661 */
731 void _stopDecelerating(num x, num y) { 662 void _stopDecelerating(num x, num y) {
732 _momentum.stop(); 663 _momentum.stop();
733 _setContentOffset(x, y); 664 _setContentOffset(x, y);
734 } 665 }
735 666
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 for (EventListener listener in _listeners) { 720 for (EventListener listener in _listeners) {
790 listener(evt); 721 listener(evt);
791 } 722 }
792 } 723 }
793 } 724 }
794 725
795 class ScrollerScrollTechnique { 726 class ScrollerScrollTechnique {
796 static final TRANSFORM_3D = 1; 727 static final TRANSFORM_3D = 1;
797 static final RELATIVE_POSITIONING = 2; 728 static final RELATIVE_POSITIONING = 2;
798 } 729 }
OLDNEW
« no previous file with comments | « client/touch/Scrollbar.dart ('k') | client/view/PagedViews.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698