| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:html'; | 6 import 'dart:html'; |
| 7 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; | 7 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| 8 import 'package:observatory/src/elements/helpers/tag.dart'; | 8 import 'package:observatory/src/elements/helpers/tag.dart'; |
| 9 | 9 |
| 10 typedef HtmlElement VirtualCollectionCreateCallback(); | 10 typedef HtmlElement VirtualCollectionCreateCallback(); |
| 11 typedef void VirtualCollectionUpdateCallback(HtmlElement el, dynamic item, | 11 typedef void VirtualCollectionUpdateCallback(HtmlElement el, dynamic item, |
| 12 int index); | 12 int index); |
| 13 | 13 |
| 14 class VirtualCollectionElement extends HtmlElement implements Renderable { | 14 class VirtualCollectionElement extends HtmlElement implements Renderable { |
| 15 static const tag = | 15 static const tag = |
| 16 const Tag<VirtualCollectionElement>('virtual-collection'); | 16 const Tag<VirtualCollectionElement>('virtual-collection'); |
| 17 | 17 |
| 18 RenderingScheduler<VirtualCollectionElement> _r; | 18 RenderingScheduler<VirtualCollectionElement> _r; |
| 19 | 19 |
| 20 Stream<RenderedEvent<VirtualCollectionElement>> get onRendered => | 20 Stream<RenderedEvent<VirtualCollectionElement>> get onRendered => |
| 21 _r.onRendered; | 21 _r.onRendered; |
| 22 | 22 |
| 23 VirtualCollectionCreateCallback _create; | 23 VirtualCollectionCreateCallback _create; |
| 24 VirtualCollectionCreateCallback _createHeader; | 24 VirtualCollectionCreateCallback _createHeader; |
| 25 VirtualCollectionUpdateCallback _update; | 25 VirtualCollectionUpdateCallback _update; |
| 26 double _itemHeight; | 26 double _itemHeight; |
| 27 double _headerHeight = 0.0; |
| 27 int _top; | 28 int _top; |
| 28 double _height; | 29 double _height; |
| 29 List _items; | 30 List _items; |
| 30 StreamSubscription _onScrollSubscription; | 31 StreamSubscription _onScrollSubscription; |
| 31 StreamSubscription _onResizeSubscription; | 32 StreamSubscription _onResizeSubscription; |
| 32 | 33 |
| 33 List get items => _items; | 34 List get items => _items; |
| 34 | 35 |
| 35 set items(Iterable value) { | 36 set items(Iterable value) { |
| 36 _items = new List.unmodifiable(value); | 37 _items = new List.unmodifiable(value); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 static const int _preload = 2; | 100 static const int _preload = 2; |
| 100 /// L = length of all the elements loaded | 101 /// L = length of all the elements loaded |
| 101 /// l = length of the visible area | 102 /// l = length of the visible area |
| 102 /// | 103 /// |
| 103 /// L = l + 2 * l / _preload | 104 /// L = l + 2 * l / _preload |
| 104 /// l = L * _preload / (_preload + 2) | 105 /// l = L * _preload / (_preload + 2) |
| 105 /// | 106 /// |
| 106 /// tail = l / _preload = L * 1 / (_preload + 2) = L * _inverse_preload | 107 /// tail = l / _preload = L * 1 / (_preload + 2) = L * _inverse_preload |
| 107 static const double _inverse_preload = 1 / (_preload + 2); | 108 static const double _inverse_preload = 1 / (_preload + 2); |
| 108 | 109 |
| 110 var _takeIntoView; |
| 111 |
| 112 void takeIntoView(item) { |
| 113 _takeIntoView = item; |
| 114 _r.dirty(); |
| 115 } |
| 116 |
| 109 void render() { | 117 void render() { |
| 110 if (children.isEmpty) { | 118 if (children.isEmpty) { |
| 111 children = [ | 119 children = [ |
| 112 _scroller | 120 _scroller |
| 113 ..children = [ | 121 ..children = [ |
| 114 _shifter | 122 _shifter |
| 115 ..children = [_create()] | 123 ..children = [_create()] |
| 116 ], | 124 ], |
| 117 ]; | 125 ]; |
| 118 if (_createHeader != null) { | 126 if (_createHeader != null) { |
| 119 _header.children = [_createHeader()]; | 127 _header.children = [_createHeader()]; |
| 120 _scroller.children.insert(0, _header); | 128 _scroller.children.insert(0, _header); |
| 129 _headerHeight = _header.children[0].getBoundingClientRect().height; |
| 121 } | 130 } |
| 122 _itemHeight = _shifter.children[0].getBoundingClientRect().height; | 131 _itemHeight = _shifter.children[0].getBoundingClientRect().height; |
| 123 _height = getBoundingClientRect().height; | 132 _height = getBoundingClientRect().height; |
| 124 } | 133 } |
| 134 |
| 135 if (_takeIntoView != null) { |
| 136 final index = items.indexOf(_takeIntoView); |
| 137 if (index >= 0) { |
| 138 final minScrollTop = _itemHeight * (index + 1) - _height; |
| 139 final maxScrollTop = _itemHeight * index; |
| 140 scrollTop = ((maxScrollTop - minScrollTop) / 2 + minScrollTop).floor(); |
| 141 } |
| 142 _takeIntoView = null; |
| 143 } |
| 144 |
| 125 final top = (scrollTop / _itemHeight).floor(); | 145 final top = (scrollTop / _itemHeight).floor(); |
| 126 | 146 |
| 127 _header.style.top = '${scrollTop}px'; | 147 _header.style.top = '${scrollTop}px'; |
| 128 _scroller.style.height = '${_itemHeight*(_items.length)}px'; | 148 _scroller.style.height = '${_itemHeight*(_items.length)+_headerHeight}px'; |
| 129 final tail_length = (_height / _itemHeight / _preload).ceil(); | 149 final tail_length = (_height / _itemHeight / _preload).ceil(); |
| 130 final length = tail_length * 2 + tail_length * _preload; | 150 final length = tail_length * 2 + tail_length * _preload; |
| 131 | 151 |
| 132 if (_shifter.children.length < length) { | 152 if (_shifter.children.length < length) { |
| 133 while (_shifter.children.length != length) { | 153 while (_shifter.children.length != length) { |
| 134 var e = _create(); | 154 var e = _create(); |
| 135 e..style.display = 'hidden'; | 155 e..style.display = 'hidden'; |
| 136 _shifter.children.add(e); | 156 _shifter.children.add(e); |
| 137 } | 157 } |
| 138 _top = null; // force update; | 158 _top = null; // force update; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 159 } | 179 } |
| 160 | 180 |
| 161 void _onResize(_) { | 181 void _onResize(_) { |
| 162 final newHeight = getBoundingClientRect().height; | 182 final newHeight = getBoundingClientRect().height; |
| 163 if (newHeight > _height) { | 183 if (newHeight > _height) { |
| 164 _height = newHeight; | 184 _height = newHeight; |
| 165 _r.dirty(); | 185 _r.dirty(); |
| 166 } | 186 } |
| 167 } | 187 } |
| 168 } | 188 } |
| OLD | NEW |