DataViewTransition.html
13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The source code</title>
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
<style type="text/css">
.highlight { display: block; background-color: #ddd; }
</style>
<script type="text/javascript">
function highlight() {
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
}
</script>
</head>
<body onload="prettyPrint(); highlight();">
<pre class="prettyprint lang-js"><span id='Ext-ux-DataViewTransition'>/**
</span> * @class Ext.ux.DataViewTransition
* @extends Object
* @author Ed Spencer (http://sencha.com)
* Transition plugin for DataViews
*/
Ext.ux.DataViewTransition = Ext.extend(Object, {
<span id='Ext-ux-DataViewTransition-property-defaults'> /**
</span> * @property defaults
* @type Object
* Default configuration options for all DataViewTransition instances
*/
defaults: {
duration : 750,
idProperty: 'id'
},
<span id='Ext-ux-DataViewTransition-method-constructor'> /**
</span> * Creates the plugin instance, applies defaults
* @constructor
* @param {Object} config Optional config object
*/
constructor: function(config) {
Ext.apply(this, config || {}, this.defaults);
},
<span id='Ext-ux-DataViewTransition-method-init'> /**
</span> * Initializes the transition plugin. Overrides the dataview's default refresh function
* @param {Ext.view.View} dataview The dataview
*/
init: function(dataview) {
<span id='Ext-ux-DataViewTransition-property-dataview'> /**
</span> * @property dataview
* @type Ext.view.View
* Reference to the DataView this instance is bound to
*/
this.dataview = dataview;
var idProperty = this.idProperty;
dataview.blockRefresh = true;
dataview.updateIndexes = Ext.Function.createSequence(dataview.updateIndexes, function() {
this.getTargetEl().select(this.itemSelector).each(function(element, composite, index) {
element.id = element.dom.id = Ext.util.Format.format("{0}-{1}", dataview.id, dataview.store.getAt(index).get(idProperty));
}, this);
}, dataview);
<span id='Ext-ux-DataViewTransition-property-dataviewID'> /**
</span> * @property dataviewID
* @type String
* The string ID of the DataView component. This is used internally when animating child objects
*/
this.dataviewID = dataview.id;
<span id='Ext-ux-DataViewTransition-property-cachedStoreData'> /**
</span> * @property cachedStoreData
* @type Object
* A cache of existing store data, keyed by id. This is used to determine
* whether any items were added or removed from the store on data change
*/
this.cachedStoreData = {};
//var store = dataview.store;
//catch the store data with the snapshot immediately
this.cacheStoreData(dataview.store.snapshot);
dataview.store.on('datachanged', function(store) {
var parentEl = dataview.getTargetEl(),
calcItem = store.getAt(0),
added = this.getAdded(store),
removed = this.getRemoved(store),
previous = this.getRemaining(store),
existing = Ext.apply({}, previous, added);
//hide old items
Ext.each(removed, function(item) {
Ext.fly(this.dataviewID + '-' + item.get(this.idProperty)).animate({
remove : false,
duration: duration,
opacity : 0,
useDisplay: true
});
}, this);
//store is empty
if (calcItem == undefined) {
this.cacheStoreData(store);
return;
}
var el = Ext.get(this.dataviewID + "-" + calcItem.get(this.idProperty));
//calculate the number of rows and columns we have
var itemCount = store.getCount(),
itemWidth = el.getMargin('lr') + el.getWidth(),
itemHeight = el.getMargin('bt') + el.getHeight(),
dvWidth = parentEl.getWidth(),
columns = Math.floor(dvWidth / itemWidth),
rows = Math.ceil(itemCount / columns),
currentRows = Math.ceil(this.getExistingCount() / columns);
//make sure the correct styles are applied to the parent element
parentEl.applyStyles({
display : 'block',
position: 'relative'
});
//stores the current top and left values for each element (discovered below)
var oldPositions = {},
newPositions = {},
elCache = {};
//find current positions of each element and save a reference in the elCache
Ext.iterate(previous, function(id, item) {
var id = item.get(this.idProperty),
el = elCache[id] = Ext.get(this.dataviewID + '-' + id);
oldPositions[id] = {
top : el.getTop() - parentEl.getTop() - el.getMargin('t') - parentEl.getPadding('t'),
left: el.getLeft() - parentEl.getLeft() - el.getMargin('l') - parentEl.getPadding('l')
};
}, this);
//set absolute positioning on all DataView items. We need to set position, left and
//top at the same time to avoid any flickering
Ext.iterate(previous, function(id, item) {
var oldPos = oldPositions[id],
el = elCache[id];
if (el.getStyle('position') != 'absolute') {
elCache[id].applyStyles({
position: 'absolute',
left : oldPos.left + "px",
top : oldPos.top + "px",
//we set the width here to make ListViews work correctly. This is not needed for DataViews
width : el.getWidth(!Ext.isIE || Ext.isStrict),
height : el.getHeight(!Ext.isIE || Ext.isStrict)
});
}
});
//get new positions
var index = 0;
Ext.iterate(store.data.items, function(item) {
var id = item.get(idProperty),
el = elCache[id];
var column = index % columns,
row = Math.floor(index / columns),
top = row * itemHeight,
left = column * itemWidth;
newPositions[id] = {
top : top,
left: left
};
index ++;
}, this);
//do the movements
var startTime = new Date(),
duration = this.duration,
dataviewID = this.dataviewID;
var doAnimate = function() {
var elapsed = new Date() - startTime,
fraction = elapsed / duration;
if (fraction >= 1) {
for (var id in newPositions) {
Ext.fly(dataviewID + '-' + id).applyStyles({
top : newPositions[id].top + "px",
left: newPositions[id].left + "px"
});
}
Ext.TaskManager.stop(task);
} else {
//move each item
for (var id in newPositions) {
if (!previous[id]) continue;
var oldPos = oldPositions[id],
newPos = newPositions[id],
oldTop = oldPos.top,
newTop = newPos.top,
oldLeft = oldPos.left,
newLeft = newPos.left,
diffTop = fraction * Math.abs(oldTop - newTop),
diffLeft= fraction * Math.abs(oldLeft - newLeft),
midTop = oldTop > newTop ? oldTop - diffTop : oldTop + diffTop,
midLeft = oldLeft > newLeft ? oldLeft - diffLeft : oldLeft + diffLeft;
Ext.fly(dataviewID + '-' + id).applyStyles({
top : midTop + "px",
left: midLeft + "px"
});
}
}
};
var task = {
run : doAnimate,
interval: 20,
scope : this
};
Ext.TaskManager.start(task);
//<debug>
var count = 0;
for (var k in added) {
count++;
}
if (Ext.global.console && Ext.global.console.log) {
Ext.global.console.log('added:', count);
}
//</debug>
//show new items
Ext.iterate(added, function(id, item) {
Ext.fly(this.dataviewID + '-' + item.get(this.idProperty)).applyStyles({
top : newPositions[item.get(this.idProperty)].top + "px",
left : newPositions[item.get(this.idProperty)].left + "px"
});
Ext.fly(this.dataviewID + '-' + item.get(this.idProperty)).animate({
remove : false,
duration: duration,
opacity : 1
});
}, this);
this.cacheStoreData(store);
}, this);
},
<span id='Ext-ux-DataViewTransition-method-cacheStoreData'> /**
</span> * Caches the records from a store locally for comparison later
* @param {Ext.data.Store} store The store to cache data from
*/
cacheStoreData: function(store) {
this.cachedStoreData = {};
store.each(function(record) {
this.cachedStoreData[record.get(this.idProperty)] = record;
}, this);
},
<span id='Ext-ux-DataViewTransition-method-getExisting'> /**
</span> * Returns all records that were already in the DataView
* @return {Object} All existing records
*/
getExisting: function() {
return this.cachedStoreData;
},
<span id='Ext-ux-DataViewTransition-method-getExistingCount'> /**
</span> * Returns the total number of items that are currently visible in the DataView
* @return {Number} The number of existing items
*/
getExistingCount: function() {
var count = 0,
items = this.getExisting();
for (var k in items) count++;
return count;
},
<span id='Ext-ux-DataViewTransition-method-getAdded'> /**
</span> * Returns all records in the given store that were not already present
* @param {Ext.data.Store} store The updated store instance
* @return {Object} Object of records not already present in the dataview in format {id: record}
*/
getAdded: function(store) {
var added = {};
store.each(function(record) {
if (this.cachedStoreData[record.get(this.idProperty)] == undefined) {
added[record.get(this.idProperty)] = record;
}
}, this);
return added;
},
<span id='Ext-ux-DataViewTransition-method-getRemoved'> /**
</span> * Returns all records that are present in the DataView but not the new store
* @param {Ext.data.Store} store The updated store instance
* @return {Array} Array of records that used to be present
*/
getRemoved: function(store) {
var removed = [];
for (var id in this.cachedStoreData) {
if (store.findExact(this.idProperty, Number(id)) == -1) {
removed.push(this.cachedStoreData[id]);
}
}
return removed;
},
<span id='Ext-ux-DataViewTransition-method-getRemaining'> /**
</span> * Returns all records that are already present and are still present in the new store
* @param {Ext.data.Store} store The updated store instance
* @return {Object} Object of records that are still present from last time in format {id: record}
*/
getRemaining: function(store) {
var remaining = {};
store.each(function(record) {
if (this.cachedStoreData[record.get(this.idProperty)] != undefined) {
remaining[record.get(this.idProperty)] = record;
}
}, this);
return remaining;
}
});
</pre>
</body>
</html>