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

Side by Side Diff: runtime/observatory/lib/src/elements/containers/virtual_collection.dart

Issue 2991203002: Fix Observatory virtual-collection layout issues (Closed)
Patch Set: Fix persistent handles page Created 3 years, 4 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 (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 List<HtmlElement> VirtualCollectionHeaderCallback();
11 typedef void VirtualCollectionUpdateCallback( 12 typedef void VirtualCollectionUpdateCallback(
12 HtmlElement el, dynamic item, int index); 13 HtmlElement el, dynamic item, int index);
13 14
14 class VirtualCollectionElement extends HtmlElement implements Renderable { 15 class VirtualCollectionElement extends HtmlElement implements Renderable {
15 static const tag = const Tag<VirtualCollectionElement>('virtual-collection'); 16 static const tag = const Tag<VirtualCollectionElement>('virtual-collection');
16 17
17 RenderingScheduler<VirtualCollectionElement> _r; 18 RenderingScheduler<VirtualCollectionElement> _r;
18 19
19 Stream<RenderedEvent<VirtualCollectionElement>> get onRendered => 20 Stream<RenderedEvent<VirtualCollectionElement>> get onRendered =>
20 _r.onRendered; 21 _r.onRendered;
21 22
22 VirtualCollectionCreateCallback _create; 23 VirtualCollectionCreateCallback _create;
23 VirtualCollectionCreateCallback _createHeader; 24 VirtualCollectionHeaderCallback _createHeader;
24 VirtualCollectionUpdateCallback _update; 25 VirtualCollectionUpdateCallback _update;
25 double _itemHeight; 26 double _itemHeight;
26 double _headerHeight = 0.0; 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);
37 _top = null; 38 _top = null;
38 _r.dirty(); 39 _r.dirty();
39 } 40 }
40 41
41 factory VirtualCollectionElement(VirtualCollectionCreateCallback create, 42 factory VirtualCollectionElement(VirtualCollectionCreateCallback create,
42 VirtualCollectionUpdateCallback update, 43 VirtualCollectionUpdateCallback update,
43 {Iterable items: const [], 44 {Iterable items: const [],
44 VirtualCollectionCreateCallback createHeader, 45 VirtualCollectionHeaderCallback createHeader,
45 RenderingQueue queue}) { 46 RenderingQueue queue}) {
46 assert(create != null); 47 assert(create != null);
47 assert(update != null); 48 assert(update != null);
48 assert(items != null); 49 assert(items != null);
49 VirtualCollectionElement e = document.createElement(tag.name); 50 VirtualCollectionElement e = document.createElement(tag.name);
50 e._r = new RenderingScheduler(e, queue: queue); 51 e._r = new RenderingScheduler(e, queue: queue);
51 e._create = create; 52 e._create = create;
52 e._createHeader = createHeader; 53 e._createHeader = createHeader;
53 e._update = update; 54 e._update = update;
54 e._items = new List.unmodifiable(items); 55 e._items = new List.unmodifiable(items);
(...skipping 17 matching lines...) Expand all
72 super.detached(); 73 super.detached();
73 _r.disable(notify: true); 74 _r.disable(notify: true);
74 children = const []; 75 children = const [];
75 _onScrollSubscription.cancel(); 76 _onScrollSubscription.cancel();
76 _onResizeSubscription.cancel(); 77 _onResizeSubscription.cancel();
77 } 78 }
78 79
79 final DivElement _header = new DivElement()..classes = ['header']; 80 final DivElement _header = new DivElement()..classes = ['header'];
80 final DivElement _scroller = new DivElement()..classes = ['scroller']; 81 final DivElement _scroller = new DivElement()..classes = ['scroller'];
81 final DivElement _shifter = new DivElement()..classes = ['shifter']; 82 final DivElement _shifter = new DivElement()..classes = ['shifter'];
83 final DivElement _container = new DivElement()..classes = ['container'];
82 84
83 dynamic getItemFromElement(HtmlElement element) { 85 dynamic getItemFromElement(HtmlElement element) {
84 final el_index = _shifter.children.indexOf(element); 86 final el_index = _container.children.indexOf(element);
85 if (el_index < 0) { 87 if (el_index < 0) {
86 return null; 88 return null;
87 } 89 }
88 final item_index = 90 final item_index = _top +
89 _top + el_index - (_shifter.children.length * _inverse_preload).floor(); 91 el_index -
92 (_container.children.length * _inverse_preload).floor();
90 if (0 <= item_index && item_index < items.length) { 93 if (0 <= item_index && item_index < items.length) {
91 return _items[item_index]; 94 return _items[item_index];
92 } 95 }
93 return null; 96 return null;
94 } 97 }
95 98
96 /// The preloaded element before and after the visible area are: 99 /// The preloaded element before and after the visible area are:
97 /// 1/preload_size of the number of items in the visble area. 100 /// 1/preload_size of the number of items in the visble area.
98 /// See shared.css for the "top:-25%;". 101 /// See shared.css for the "top:-25%;".
99 static const int _preload = 2; 102 static const int _preload = 2;
(...skipping 12 matching lines...) Expand all
112 void takeIntoView(item) { 115 void takeIntoView(item) {
113 _takeIntoView = item; 116 _takeIntoView = item;
114 _r.dirty(); 117 _r.dirty();
115 } 118 }
116 119
117 void render() { 120 void render() {
118 if (children.isEmpty) { 121 if (children.isEmpty) {
119 children = [ 122 children = [
120 _scroller 123 _scroller
121 ..children = [ 124 ..children = [
122 _shifter..children = [_create()] 125 _shifter
126 ..children = [
127 _container..children = [_create()]
128 ]
123 ], 129 ],
124 ]; 130 ];
125 if (_createHeader != null) { 131 if (_createHeader != null) {
126 _header.children = [_createHeader()]; 132 _header.children = [
133 new DivElement()
134 ..classes = ['container']
135 ..children = _createHeader()
136 ];
127 _scroller.children.insert(0, _header); 137 _scroller.children.insert(0, _header);
128 _headerHeight = _header.children[0].getBoundingClientRect().height; 138 _headerHeight = _header.children[0].getBoundingClientRect().height;
129 } 139 }
130 _itemHeight = _shifter.children[0].getBoundingClientRect().height; 140 _itemHeight = _container.children[0].getBoundingClientRect().height;
131 _height = getBoundingClientRect().height; 141 _height = getBoundingClientRect().height;
132 } 142 }
133 143
134 if (_takeIntoView != null) { 144 if (_takeIntoView != null) {
135 final index = items.indexOf(_takeIntoView); 145 final index = items.indexOf(_takeIntoView);
136 if (index >= 0) { 146 if (index >= 0) {
137 final minScrollTop = _itemHeight * (index + 1) - _height; 147 final minScrollTop = _itemHeight * (index + 1) - _height;
138 final maxScrollTop = _itemHeight * index; 148 final maxScrollTop = _itemHeight * index;
139 scrollTop = ((maxScrollTop - minScrollTop) / 2 + minScrollTop).floor(); 149 scrollTop = ((maxScrollTop - minScrollTop) / 2 + minScrollTop).floor();
140 } 150 }
141 _takeIntoView = null; 151 _takeIntoView = null;
142 } 152 }
143 153
144 final top = (scrollTop / _itemHeight).floor(); 154 final top = (scrollTop / _itemHeight).floor();
145 155
146 _header.style.top = '${scrollTop}px'; 156 _header.style.top = '${scrollTop}px';
147 _scroller.style.height = '${_itemHeight*(_items.length)+_headerHeight}px'; 157 _scroller.style.height = '${_itemHeight*(_items.length)+_headerHeight}px';
148 final tail_length = (_height / _itemHeight / _preload).ceil(); 158 final tail_length = (_height / _itemHeight / _preload).ceil();
149 final length = tail_length * 2 + tail_length * _preload; 159 final length = tail_length * 2 + tail_length * _preload;
150 160
151 if (_shifter.children.length < length) { 161 if (_container.children.length < length) {
152 while (_shifter.children.length != length) { 162 while (_container.children.length != length) {
153 var e = _create(); 163 var e = _create();
154 e..style.display = 'hidden'; 164 e..style.display = 'hidden';
155 _shifter.children.add(e); 165 _container.children.add(e);
156 } 166 }
157 _top = null; // force update; 167 _top = null; // force update;
158 } 168 }
159 169
160 if ((_top == null) || ((top - _top).abs() >= tail_length)) { 170 if ((_top == null) || ((top - _top).abs() >= tail_length)) {
161 _shifter.style.top = '${_itemHeight*(top-tail_length)}px'; 171 _shifter.style.top = '${_itemHeight*(top-tail_length)}px';
162 int i = top - tail_length; 172 int i = top - tail_length;
163 for (final HtmlElement e in _shifter.children) { 173 for (final HtmlElement e in _container.children) {
164 if (0 <= i && i < _items.length) { 174 if (0 <= i && i < _items.length) {
165 e..style.display = null; 175 e..style.display = null;
166 _update(e, _items[i], i); 176 _update(e, _items[i], i);
167 } else { 177 } else {
168 e.style.display = 'hidden'; 178 e.style.display = 'hidden';
169 } 179 }
170 i++; 180 i++;
171 } 181 }
172 _top = top; 182 _top = top;
173 } 183 }
174 } 184 }
175 185
176 void _onScroll(_) { 186 void _onScroll(_) {
177 _r.dirty(); 187 _r.dirty();
178 } 188 }
179 189
180 void _onResize(_) { 190 void _onResize(_) {
181 final newHeight = getBoundingClientRect().height; 191 final newHeight = getBoundingClientRect().height;
182 if (newHeight > _height) { 192 if (newHeight > _height) {
183 _height = newHeight; 193 _height = newHeight;
184 _r.dirty(); 194 _r.dirty();
185 } 195 }
186 } 196 }
187 } 197 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698