Mercurial > pub > ImplabJs
comparison src/djol/VectorStore.js @ 34:27e8e9e38e07 default tip
Слияние
author | nickolay |
---|---|
date | Wed, 05 Jun 2019 20:44:15 +0300 |
parents | 8af8e840dd49 1dc2fd263b90 |
children |
comparison
equal
deleted
inserted
replaced
33:8af8e840dd49 | 34:27e8e9e38e07 |
---|---|
1 define( | |
2 [ | |
3 "dojo/_base/declare", | |
4 "dojo/_base/array", | |
5 "implab/safe", | |
6 "implab/Uuid", | |
7 "ol", | |
8 "ol3/listen", | |
9 "./VectorStoreQuery", | |
10 "dojo/store/util/QueryResults" | |
11 ], | |
12 function (declare, array, safe, UUID, ol, listen, VectorStoreQuery, QueryResults) { | |
13 function createPaginator(opts) { | |
14 return (opts.count || opts.start) && | |
15 function (results) { | |
16 var total = results.length; | |
17 results = results.slice(opts.start || 0, (opts.start || 0) + | |
18 (opts.count || Infinity)); | |
19 results.total = total; | |
20 | |
21 return results; | |
22 }; | |
23 } | |
24 | |
25 /** | |
26 * Обертка вокруг векторного источника данных ol.source.Vector, | |
27 * реализует dojo/store а также notify, что делает возможным наблюдение | |
28 * за хранилищем при помощи dojo/store/Observable. | |
29 * | |
30 * @disposable | |
31 */ | |
32 return declare( | |
33 null, { | |
34 _source: null, // ol3.source.Vector | |
35 | |
36 _projection: null, | |
37 | |
38 _subscriptions: null, | |
39 | |
40 constructor: function (opts) { | |
41 safe.argumentNotNull(opts, "opts"); | |
42 safe.argumentOfType( | |
43 opts.source, | |
44 ol.source.Vector, | |
45 "opts.source"); | |
46 | |
47 var me = this; | |
48 | |
49 me._source = opts.source; | |
50 if (opts.projection) | |
51 me._projection = ol.proj.get(opts.projection); | |
52 }, | |
53 | |
54 getSource: function () { | |
55 return this._source; | |
56 }, | |
57 | |
58 getProjection: function() { | |
59 return this._projection; | |
60 }, | |
61 | |
62 get: function (id) { | |
63 return this._source.getFeatureById(id); | |
64 }, | |
65 | |
66 /** | |
67 * @param{Object|Function} q предикат для выбора объекта | |
68 * @param{Object} opts параметры выполнения (start,count,sort) | |
69 * @return{Function} filter(data) filter.matches | |
70 * filter.matches.predicate | |
71 * filter.matches.extent filter.sort | |
72 * filter.sort.compare | |
73 */ | |
74 queryEngine: function (q, opts) { | |
75 opts = opts || {}; | |
76 | |
77 // строим функцию для фильтрации | |
78 var filter; | |
79 if (q instanceof Function) { | |
80 // если передали уже готовую функцию, испольуем ее | |
81 filter = new VectorStoreQuery(q, q.extent); | |
82 } else { | |
83 // если передали объект | |
84 var extent; | |
85 // вытаскиваем из него extent | |
86 if (q && 'extent' in q) { | |
87 extent = q.extent; | |
88 delete q.extent; | |
89 } | |
90 | |
91 // строим новую функцию фильтрации | |
92 filter = new VectorStoreQuery(q, extent); | |
93 } | |
94 | |
95 // строим функцию сортировки | |
96 var sort = opts.sort && this.sortEngine(opts.sort); | |
97 | |
98 var paginate = createPaginator(opts); | |
99 | |
100 // строим функцию выполнения запроса | |
101 var execute = function (data) { | |
102 var results = array.filter(data, filter); | |
103 | |
104 if (sort) | |
105 sort(results); | |
106 | |
107 if (paginate) | |
108 results = paginate(results); | |
109 return results; | |
110 }; | |
111 | |
112 execute.matches = filter; | |
113 execute.sort = sort; | |
114 execute.paginate = paginate; | |
115 return execute; | |
116 }, | |
117 | |
118 sortEngine: function (options) { | |
119 var cmp = function (a, b) { | |
120 for (var sort, i = 0; | |
121 (sort = options[i]); i++) { | |
122 var aValue = a.get(sort.attribute); | |
123 var bValue = b.get(sort.attribute); | |
124 if (aValue != bValue) { | |
125 return Boolean(sort.descending) == aValue > bValue ? -1 : 1; | |
126 } | |
127 } | |
128 return 0; | |
129 }; | |
130 | |
131 var execute = function (data) { | |
132 return data.sort(cmp); | |
133 }; | |
134 | |
135 execute.compare = cmp; | |
136 return execute; | |
137 }, | |
138 | |
139 /** | |
140 * Запрашивает объекты со слоя | |
141 * | |
142 * @param{object|VectorStoreQuery|Function} query | |
143 * | |
144 * <pre> | |
145 * { | |
146 * extent : ol3.Extent, | |
147 * } | |
148 * </pre> | |
149 */ | |
150 query: function (q, options) { | |
151 var me = this; | |
152 var filter = this.queryEngine(q, options); | |
153 | |
154 if (this.notify && !this.hasOwnProperty("_subscriptions")) { | |
155 me._subscriptions = []; | |
156 | |
157 var sc = function (evt, handler) { | |
158 me._subscriptions.push(listen(me._source, evt, safe.delegate(me, handler))); | |
159 } | |
160 | |
161 sc("addfeature", "_onAdd"); | |
162 sc("changefeature", "_onUpdate"); | |
163 sc("removefeature", "_onRemove"); | |
164 } | |
165 | |
166 var predicate, data, extent = filter.matches && | |
167 filter.matches.extent; | |
168 // если это запрос с указанием области | |
169 if (extent) { | |
170 predicate = filter.matches.predicate; | |
171 | |
172 data = this._source.getFeaturesInExtent(extent); | |
173 | |
174 if (predicate) | |
175 data = array.filter(data, predicate); | |
176 | |
177 if (filter.sort) | |
178 filter.sort(data); | |
179 | |
180 if (filter.paginate) | |
181 data = filter.paginate(data); | |
182 } else { | |
183 // любой другой запрос | |
184 data = filter(this._source.getFeatures()); | |
185 } | |
186 | |
187 return new QueryResults(data); | |
188 }, | |
189 | |
190 put: function (obj, options) { | |
191 safe.argumentOfType(obj, ol.Feature, "obj"); | |
192 if (!options) | |
193 options = {}; | |
194 | |
195 if (options.id) | |
196 obj.setId(options.id); | |
197 | |
198 var id = obj.getId() || new UUID(); | |
199 | |
200 var prev = this.get(id); | |
201 | |
202 if ('overwrite' in options) { | |
203 // overwrite=true указан, но перезаписывать нечего | |
204 if (!prev && options.overwrite) | |
205 throw new Error("The specified feature with id '" + | |
206 id + "' doesn't exist in the store"); | |
207 | |
208 // overwrite=false указан, но объект уже существует | |
209 if (prev && !options.overwrite) | |
210 throw new Error("The specified feature with id '" + | |
211 id + "' already exists in the store"); | |
212 } | |
213 | |
214 // ok | |
215 if (prev) { | |
216 var data = obj.getProperties(); | |
217 prev.setProperties(data); | |
218 } else { | |
219 this._source.addFeature(obj); | |
220 } | |
221 | |
222 return id; | |
223 }, | |
224 | |
225 add: function (obj, options) { | |
226 safe.argumentOfType(obj, ol.Feature, "obj"); | |
227 | |
228 if (!options) | |
229 options = {}; | |
230 | |
231 if (options.id) | |
232 obj.setId(options.id); | |
233 | |
234 var id = obj.getId() || new UUID(); | |
235 | |
236 var prev = this.get(id); | |
237 | |
238 if (prev) | |
239 throw new Error("The specified feature with id '" + id + | |
240 "' already exists in the store"); | |
241 | |
242 this._source.addFeature(obj); | |
243 }, | |
244 | |
245 remove: function (id) { | |
246 var me = this; | |
247 | |
248 var ft = me.get(id); | |
249 if (ft) | |
250 me._source.removeFeature(ft); | |
251 }, | |
252 | |
253 getIdentity: function (obj) { | |
254 if (safe.isNull(obj)) | |
255 return undefined; | |
256 if (!(obj instanceof ol.Feature)) | |
257 throw new Error("A feature is expected"); | |
258 | |
259 return obj.getId(); | |
260 }, | |
261 | |
262 _onAdd: function (ev) { | |
263 this.notify(ev.feature); | |
264 }, | |
265 | |
266 _onRemove: function (ev) { | |
267 var id = ev.feature.getId(); | |
268 if (!safe.isNull(id)) | |
269 this.notify(undefined, id); | |
270 }, | |
271 | |
272 _onUpdate: function (ev) { | |
273 var id = ev.feature.getId(); | |
274 if (!safe.isNull(id)) | |
275 this.notify(ev.feature, id); | |
276 }, | |
277 | |
278 dispose: function () { | |
279 var me = this; | |
280 if (me._subscriptions) | |
281 me._subscriptions.forEach(function (sc) { | |
282 sc.remove(); | |
283 }); | |
284 | |
285 me._source = null; | |
286 me._subscriptions = null; | |
287 } | |
288 }); | |
289 }); |