Mercurial > pub > ImplabJs
diff src/djol/VectorStore.js @ 10:8705103f074f
Слияние
author | cin |
---|---|
date | Mon, 21 Aug 2017 18:03:00 +0300 |
parents | f0035923ff3e |
children | 60f6493e2892 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/VectorStore.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,281 @@ +define( + [ + "dojo/_base/declare", + "dojo/_base/array", + "implab/safe", + "implab/Uuid", + "ol", + "ol3/listen", + "./VectorStoreQuery", + "dojo/store/util/QueryResults" + ], + function (declare, array, safe, UUID, ol, listen, VectorStoreQuery, QueryResults) { + function createPaginator(opts) { + return (opts.count || opts.start) && + function (results) { + var total = results.length; + results = results.slice(opts.start || 0, (opts.start || 0) + + (opts.count || Infinity)); + results.total = total; + + return results; + }; + } + + /** + * Обертка вокруг векторного источника данных ol.source.Vector, + * реализует dojo/store а также notify, что делает возможным наблюдение + * за хранилищем при помощи dojo/store/Observable. + * + * @disposable + */ + return declare( + null, { + _source: null, // ol3.source.Vector + + _subscriptions: null, + + constructor: function (opts) { + safe.argumentNotNull(opts, "opts"); + safe.argumentOfType( + opts.source, + ol.source.Vector, + "opts.source"); + + var me = this; + + me._source = opts.source; + }, + + getSource: function () { + return this._source; + }, + + get: function (id) { + return this._source.getFeatureById(id); + }, + + /** + * @param{Object|Function} q предикат для выбора объекта + * @param{Object} opts параметры выполнения (start,count,sort) + * @return{Function} filter(data) filter.matches + * filter.matches.predicate + * filter.matches.extent filter.sort + * filter.sort.compare + */ + queryEngine: function (q, opts) { + opts = opts || {}; + + // строим функцию для фильтрации + var filter; + if (q instanceof Function) { + // если передали уже готовую функцию, испольуем ее + filter = new VectorStoreQuery(q, q.extent); + } else { + // если передали объект + var extent; + // вытаскиваем из него extent + if (q && 'extent' in q) { + extent = q.extent; + delete q.extent; + } + + // строим новую функцию фильтрации + filter = new VectorStoreQuery(q, extent); + } + + // строим функцию сортировки + var sort = opts.sort && this.sortEngine(opts.sort); + + var paginate = createPaginator(opts); + + // строим функцию выполнения запроса + var execute = function (data) { + var results = array.filter(data, filter); + + if (sort) + sort(results); + + if (paginate) + results = paginate(results); + return results; + }; + + execute.matches = filter; + execute.sort = sort; + execute.paginate = paginate; + return execute; + }, + + sortEngine: function (options) { + var cmp = function (a, b) { + for (var sort, i = 0; + (sort = options[i]); i++) { + var aValue = a.get(sort.attribute); + var bValue = b.get(sort.attribute); + if (aValue != bValue) { + return Boolean(sort.descending) == aValue > bValue ? -1 : 1; + } + } + return 0; + }; + + var execute = function (data) { + return data.sort(cmp); + }; + + execute.compare = cmp; + return execute; + }, + + /** + * Запрашивает объекты со слоя + * + * @param{object|VectorStoreQuery|Function} query + * + * <pre> + * { + * extent : ol3.Extent, + * } + * </pre> + */ + query: function (q, options) { + var me = this; + var filter = this.queryEngine(q, options); + + if (this.notify && !this.hasOwnProperty("_subscriptions")) { + me._subscriptions = []; + + var sc = function (evt, handler) { + me._subscriptions.push(listen(me._source, evt, safe.delegate(me, handler))); + } + + sc("addfeature", "_onAdd"); + sc("changefeature", "_onUpdate"); + sc("removefeature", "_onRemove"); + } + + var predicate, data, extent = filter.matches && + filter.matches.extent; + // если это запрос с указанием области + if (extent) { + predicate = filter.matches.predicate; + + data = this._source.getFeaturesInExtent(extent); + + if (predicate) + data = array.filter(data, predicate); + + if (filter.sort) + filter.sort(data); + + if (filter.paginate) + data = filter.paginate(data); + } else { + // любой другой запрос + data = filter(this._source.getFeatures()); + } + + return new QueryResults(data); + }, + + put: function (obj, options) { + safe.argumentOfType(obj, ol.Feature, "obj"); + if (!options) + options = {}; + + if (options.id) + obj.setId(options.id); + + var id = obj.getId() || new UUID(); + + var prev = this.get(id); + + if ('overwrite' in options) { + // overwrite=true указан, но перезаписывать нечего + if (!prev && options.overwrite) + throw new Error("The specified feature with id '" + + id + "' doesn't exist in the store"); + + // overwrite=false указан, но объект уже существует + if (prev && !options.overwrite) + throw new Error("The specified feature with id '" + + id + "' already exists in the store"); + } + + // ok + if (prev) { + var data = obj.getProperties(); + prev.setProperties(data); + } else { + this._source.addFeature(obj); + } + + return id; + }, + + add: function (obj, options) { + safe.argumentOfType(obj, ol.Feature, "obj"); + + if (!options) + options = {}; + + if (options.id) + obj.setId(options.id); + + var id = obj.getId() || new UUID(); + + var prev = this.get(id); + + if (prev) + throw new Error("The specified feature with id '" + id + + "' already exists in the store"); + + this._source.addFeature(obj); + }, + + remove: function (id) { + var me = this; + + var ft = me.get(id); + if (ft) + me._source.removeFeature(ft); + }, + + getIdentity: function (obj) { + if (safe.isNull(obj)) + return undefined; + if (!(obj instanceof ol.Feature)) + throw new Error("A feature is expected"); + + return obj.getId(); + }, + + _onAdd: function (ev) { + this.notify(ev.feature); + }, + + _onRemove: function (ev) { + var id = ev.feature.getId(); + if (!safe.isNull(id)) + this.notify(undefined, id); + }, + + _onUpdate: function (ev) { + var id = ev.feature.getId(); + if (!safe.isNull(id)) + this.notify(ev.feature, id); + }, + + dispose: function () { + var me = this; + if (me._subscriptions) + me._subscriptions.forEach(function (sc) { + sc.remove(); + }); + + me._source = null; + me._subscriptions = null; + } + }); + }); \ No newline at end of file