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 }); |
