# HG changeset patch # User cin # Date 1503327780 -10800 # Node ID 8705103f074fb2e6f61ee11d0afe66b3be3d71e6 # Parent 37e9e6bbe87acd4e08412dd80b2b27c468f7a819# Parent f0035923ff3e23ce7582cf56a3bbae9e530896f2 Слияние diff -r 37e9e6bbe87a -r 8705103f074f src/djol/BaseLayer.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/BaseLayer.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,44 @@ +define([ + "implab/text/template-compile", + "dojo/_base/declare", + "dojo/_base/lang", + "ol"], + function (compile, declare, lang, ol) { + return declare([ol.layer.Layer], { + + name: null, + + displayName: null, + + identifyResultTemplate: null, + + searchResultTemplate: null, + + constructor: function () { + lang.mixin(this, arguments[0]); + var identifyCompiledTemplate = null, searchCompiledTemplate = null; + if (this.identifyResultTemplate) { + identifyCompiledTemplate = compile(this.identifyResultTemplate); + } + if (this.searchResultTemplate) { + searchCompiledTemplate = compile(this.searchResultTemplate); + } + }, + + /** Возвращает массив строк, каждая строка - результат поиска приведенный к шаблонному виду + @options {Object} + @str {String} поисковая строка + @bbox {Object} bound box, в рамках которого осуществлять поиск + */ + getSearchResult: function (options) { + console.warn("Метод необходимо переопределить для для слоя конкретного типа!"); + }, + /** Возвращает массив строк, каждая строка - результат идентификации приведенный к шаблонному виду + @options {Object} + @coordinates {Array} массив описывающий координаты точки идентификации + */ + getItentifyResult: function (coordinates) { + console.warn("Метод необходимо переопределить для для слоя конкретного типа!"); + } + }); + }) \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/ClearTool.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/ClearTool.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,19 @@ +define (["dojo/_base/declare", "./_OneshotTool", "implab/safe"] , function(declare, _OneshotTool, safe) { + return declare([_OneshotTool], { + tools : null, + + constructor : function(opts) { + safe.mixin(this,opts, ["tools"]); + }, + + invoke : function() { + if (this.tools) { + this.log("Clear {0} tools", this.tools.length); + safe.each(this.tools, function(tool) { + if (tool.clear) + tool.clear(); + }); + } + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/DeactivationTool.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/DeactivationTool.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,14 @@ +define(["dojo/_base/declare", "./_ToolBase"],function(declare, _ToolBase) { + + // Инструмент, выключает текущий активный инструмент + // Данный инструмент ничго не делает, но при его активации будет + // деактивирован предыдущий инструмент + return declare([_ToolBase], { + + // данный инструмент не может быть активным, поэтому данный метод + // переопределяется и возвращает всегда false + onActivating : function() { + return false; + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/DistanceMeasureTool.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/DistanceMeasureTool.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,63 @@ +define([ + "dojo/_base/declare", + "implab/safe", + "./MeasureToolBase", + "implab/text/format", + "dojo/i18n!./format/nls/units", + "ol" ], + +function(declare, safe, MeasureToolBase, format, units, ol) { + return declare([ MeasureToolBase ], { + + isGeodesic : true, + + units : 'metric', + + constructor : function(opts) { + if (opts) + safe.mixin(this,opts,["isGeodesic", "units"]); + }, + + _createDraw : function(source) { + return new ol.interaction.Draw( + { + source : source, + type : "LineString", + style : this.drawStyle + }); + }, + + _formatTooltip : function(sketch, proj) { + var length = 0; + if (this.isGeodesic) { + var points = sketch.getGeometry().getCoordinates(); + var t = ol.proj.getTransform(proj, "EPSG:4326"); + for (var i = 0; i < points.length - 1; i++) { + length += this.wgs84Sphere.haversineDistance( + t(points[i]), + t(points[i + 1])); + } + } else { + length = sketch.getGeometry().getLength(); + } + + var mpu, unitName; + switch (this.units) { + case "nautical": + mpu = 1852; + unitName = units.nmiles; + break; + default: + mpu = 1000; + unitName = units.kilometers; + } + + if (length >= mpu) { + return format("{0:#.0#}{1}", length / mpu, unitName); + } else { + return format("{0:#0.0#}{1}", length, units.meters); + } + } + + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/DynamicStyle.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/DynamicStyle.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,119 @@ +define([ "./declare-style", "dojo/_base/declare", "ol", "implab/safe" ], + +function(declare, dojoDeclare, ol, safe) { + return declare([], { + _cache : null, + _getKey : null, + _getZoom : null, + + defaultStyle : null, + + style : null, + + styleFunction : null, + + filter : null, + + constructor : function(opts) { + if (opts) + dojoDeclare.safeMixin(this, opts); + + this._cache = {}; + + if (this.zoom) { + if (this.zoom instanceof Function) { + this._getZoom = this.zoom; + } else { + var levels = [], max = "max"; + for ( var p in this.zoom) { + if (safe.isNumber(this.zoom[p])) + levels.push({ + name : p, + zoom : Number(this.zoom[p]) + }); + else if (this.zoom[p] == "max") + max = p; + } + + levels.sort(function(x, y) { + return x.zoom - y.zoom; + }); + + this.zoomMax = max; + this.zoomLevels = levels; + + this._getZoom = function(z) { + for (var i = 0; i < levels.length; i++) { + if (z <= levels[i].zoom) + return levels[i].name; + } + return max; + }; + } + } else { + this._getZoom = function(z) { + return "max"; + }; + } + + if (this.key) { + if (this.key instanceof Function) { + this._getKey = this.key; + } else if (typeof this.key === "string") { + this._getKey = function(ft) { + return ft.get(this.key); + }; + } else { + this._getKey = function(ft, z) { + var k = this.key[z]; + if (k instanceof Function) + return k.call(this, ft, z); + else if (typeof k == "string") + return ft.get(k); + else + return this.defaultStyle; + }; + } + } else { + this._getKey = function() { + return this.defaultStyle; + }; + } + + if (this.style) { + if (this.style instanceof Function) { + this._style = this.style; + } else { + this._style = function(ft, res, key, zoom) { + var s = this.style[zoom]; + return s && (s instanceof Function) ? s.apply( + this, + arguments) : s; + }; + } + } + }, + + getFeatureStyle : function(ft, res) { + safe.argumentNotNull(ft, "ft"); + + if (this.filter && this.filter(ft) === false) + return null; + + var z = this._getZoom(res); + var k = this._getKey(ft, z); + + var cid = [ k, z ].join('-'); + + var style = this._cache[cid]; + if (!style) { + style = this._style ? this._style(ft, res, k, z) : null; + this._cache[cid] = style; + } + + + return safe.isNull(style) || style instanceof Array ? style : [ style ]; + } + + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/IdentificationTool.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/IdentificationTool.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,246 @@ +define([ + "dijit/layout/ContentPane", + "dojo/_base/declare", + "dojo/Deferred", + "dojo/dom-construct", + "dojo/dom-class", + "dojo/on", + "dojo/promise/all", + "dojo/when", + "implab/safe", + "ol", + "./listen", + "./IdentifyGroup", + "./_ToolBase", + "./PopupContainer" + ], + + function ( + ContentPane, + declare, + Deffered, + domConstruct, + domClass, + on, + promiseAll, + when, + safe, + ol, + listen, + IdentifyGroup, + _ToolBase, + PopupContainer) { + return declare([_ToolBase], { + /** + * массив обработчиков openLayers, которые необходимо удалить при + * деактивации + */ + _handlers: null, + /** + * widget карты + */ + _map: null, + /** + * openLayers map + */ + _olMap: null, + /** + * Массив overlays содержащих popupContainers + */ + _popupOverlays: null, + /** + * Массив popups контейнеров + */ + _popupContainers: null, + /** + * Режим работы инструмента идентификации + * + * @value {String} "single"||"multiple" + */ + mode: null, + /** + * Режимы + */ + appManager: null, + + constructor: function (options) { + safe.argumentNotNull(options, "options"); + safe.argumentNotNull(options.map, "options.map"); + safe.argumentNotNull(options.appManager, "options.appManager"); + + this._map = options.map; + this._olMap = options.map.olMap; + this._popupContainers = []; + this._popupOverlays = []; + this._handlers = []; + + this.appManager = options.appManager; + this.mode = options.mode || "single"; + }, + /** + */ + createPopupContent: function (groupWidgets) { + var contentWidget = new ContentPane(); + groupWidgets.forEach(function (groupWidget) { + if (groupWidget && !groupWidget.isEmpty()) { + contentWidget.addChild(groupWidget); + } + }); + return contentWidget; + }, + + /** + * Возвращает обещание на получение объекта с результатом идентификации + * по всем видимым режимам и информационным слоям @ options {Object} @ pixel + * {Object} - информация о точке идентификации @ coordinate {Array} - + * координаты точки иденификации + */ + getGroupsFromVisibleModules: function (options) { + var promises = []; + var modules = this.appManager.getVisibleModules(); + modules.forEach(function (module) { + promises.push.apply(promises, module + .getIdentifyResult(options)); + }); + + return promiseAll(promises).then( + function (results) { + console.log("promise all groups = ", results); + return results; + }); + }, + + identifyPosition: function (position) { + var me = this, i; + var popupContainer = null, + popupOverlay = null; + if (me.mode == "multiple") { + // TODO: создать popupContainer и popupOverlay + popupContainer = new PopupContainer({ + map: me._olMap + }); + on(popupContainer, "close", function () { + var index = me._popupContainers.indexOf(me); + me._popupContainers.splice(index, 1); + + }); + me._popupContainers.push(popupContainer); + + popupOverlay = new ol.Overlay({ + element: popupContainer.domNode, + autoPan: true, + autoPanAnimation: { + duration: 250 + } + }); + me._popupOverlays.push(popupOverlay); + me._olMap.addOverlay(popupOverlay); + + } else { + if (me._popupContainers.length > 0) { + // Берем первый + popupContainer = me._popupContainers[0]; + // Все остальные удалить + if (me._popupContainers.length > 1) { + for (i = 1; i < me._popupContainers.length; i++) { + me._popupContainers[i].destroyRecursive(); + } + me._popupContainers.splice( + 1, + me._popupContainers.length - 1); + } + } else { + // Создаем новый + popupContainer = new PopupContainer({ + map: me._olMap + }); + on(popupContainer, "close", function () { + var index = me._popupContainers.indexOf(me); + me._popupContainers.splice(index, 1); + + }); + me._popupContainers.push(popupContainer); + } + if (me._popupOverlays.length > 0) { + // Берем первый и помещаем в него popup + popupOverlay = me._popupOverlays[0]; + popupOverlay.setElement(popupContainer.domNode); + // Все остальные удалить + if (me._popupOverlays.length > 1) { + for (i = 1; i < me._popupOverlays.length; i++) { + me._olMap.removeOverlay(me._popupOverlays[i]); + } + me._popupOverlays.splice( + 1, + me._popupOverlays.length - 1) + } + } else { + // Создаем новый и помещаем в него popup + popupOverlay = new ol.Overlay({ + element: popupContainer.domNode, + autoPan: true, + autoPanAnimation: { + duration: 250 + } + }); + me._popupOverlays.push(popupOverlay); + me._olMap.addOverlay(popupOverlay); + } + } + + popupContainer.destroyDescendants(); + + popupOverlay.setPosition(position.coordinate); + + popupContainer.showOverlay(); + + when(me.getGroupsFromVisibleModules(position), function (data) { + var contentWidget = me.createPopupContent(data); + popupContainer.show(contentWidget, "only"); + popupContainer.hideOverlay(); + }); + }, + /** + * Скрыть все popups + */ + hideAllPopups: function () { + var me = this, i; + for (i = 0; i < this._popupContainers.length; i++) { + this._popupContainers[i].destroyRecursive(); + } + this._popupContainers.splice(0, this._popupContainers.length); + + for (i = 0; i < this._popupOverlays.length; i++) { + this._olMap.removeOverlay(this._popupOverlays[i]); + } + this._popupOverlays.splice(0, this._popupOverlays.length) + }, + + onActivating: function () { + var me = this; + // Обработчик для события "singleclick" по карте + var handler = listen(this._olMap, 'singleclick', function (evt) { + if (evt.originalEvent.ctrlKey) { + me.mode = "multiple"; + } else { + me.mode = "single"; + } + me.identifyPosition({ + pixel: evt.pixel, + coordinate: evt.coordinate + }); + }); + this._handlers.push(handler); + }, + + onDeactivating: function () { + var me = this; + me._handlers.forEach(function (handler) { + if (handler.remove) + handler.remove(); + + }); + this.hideAllPopups(); + }, + }) + }); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/IdentifyGroup.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/IdentifyGroup.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,89 @@ +define( + [ + "implab/safe", + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + "dijit/_WidgetsInTemplateMixin", + "dijit/layout/_LayoutWidget", + "dijit/layout/ContentPane", + "dojo/_base/declare", + "dojo/dom-construct", + "dojo/on", + "ol3/IdentifyItem" ], + function( + safe, + _WidgetBase, + _TemplatedMixin, + _WidgetsInTemplateMixin, + _LayoutWidget, + ContentPane, + declare, + domConstruct, + on, + IdentifyItem) { + + return declare( + [ _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin ], + { + + /** + */ + _empty : true, + /** + */ + layerName : null, + /** + * Шаблон всего widget + */ + templateString : "
", + + itemTemplate : "", + + title : null, + + /** + * Метод из widget.lifecycle + */ + postCreate : function() { + var me = this; + if (typeof this.title == "string") { + this.identifyItemGroupTitle.innerHTML = me.title; + } else if (me.title && me.title.placeAt) { + me.title.placeAt(me.identifyItemGroupTitle, "only"); + } else { + domConstruct.place( + me.title, + me.identifyItemGroupTitle, + "only"); + } + on(this.domNode, "click", function() { + if ("function" == typeof me.callback) { + me.callback(); + } + }); + }, + + addItem : function(options) { + safe.argumentNotNull(options, "options"); + safe.argumentNotNull(options.model, "options.model"); + + if (options.model) { + + var item = new IdentifyItem({ + title : options.title || this.itemTemplate, + model : options.model, + callback : options.callback + }); + this.addChild(item); + this._empty = false; + } else { + console + .error("Не задано необходимое свойство layerFeature"); + } + }, + + isEmpty : function() { + return this._empty; + } + }); + }); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/IdentifyItem.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/IdentifyItem.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,62 @@ +define([ + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + "dijit/Tooltip", + "dojo/_base/declare", + "dojo/date/locale", + "dojo/dom-construct", + "dojo/on" ], function(_WidgetBase, _TemplatedMixin, Tooltip, declare, + dateLocale, domConstruct, on) { + var empty = {}; + return declare([ _WidgetBase, _TemplatedMixin ], { + + callback : null, + + dateLocale : dateLocale, + + baseClass : 'identify-item', + + feature : null, + + model : empty, + + title : null, + + templateString : "
", + + constructor : function(options) { + option = options || {}; + if (options.title) + this.title = options.title; + if (options.model) + this.model = options.model; + if (options.callback) + this.callback = options.callback; + + }, + + /** + * Метод из widget.lifecycle + */ + postCreate : function() { + var me = this; + + var content = me.title instanceof Function ? me.title(me) + : me.title; + + if (typeof content == "string") { + me.domNode.innerHTML = content; + } else if (content && content.placeAt) { + content.placeAt(me.domNode, "only"); + } else { + domConstruct.place(content, me.domNode, "only"); + } + + on(me.domNode, "click", function() { + if (typeof me.callback == "function") { + me.callback(me.model); + } + }); + }, + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/ImageLayer.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/ImageLayer.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,3 @@ +define(["ol"], function(ol) { + return ol.layer.Image +}) \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/ImageWMSSource.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/ImageWMSSource.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,3 @@ +define(["ol"], function(ol) { + return ol.source.ImageWMS; +}) \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/LayerCheckBox.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/LayerCheckBox.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,49 @@ +define([ + "dojo/_base/declare", + "dijit/_WidgetBase", + "dijit/_TemplatedMixin", + "dijit/_WidgetsInTemplateMixin", + "dojo/text!./resources/LayerCheckBoxTemplate.html", + "dijit/form/CheckBox" ], function(declare, _WidgetBase, _TemplatedMixin, + _WidgetsInTemplateMixin, templateString) { + return declare([ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin ], { + templateString : templateString, + labelNode : null, + checkBox : null, + + label : "", + _setLabelAttr : { + node : "labelNode", + type : "innerHTML" + }, + + name : "layer", + + _layer : null, + + constructor : function(options) { + options = options || {}; + + if (!options.layer) + throw new Error("The layer is required"); + + this._layer = options.layer; + this.label = options.layer.get("label") || "unnamed"; + }, + + postCreate : function() { + var me = this; + me.inherited(arguments); + + me.checkBox.set('name', me.name); + me.checkBox.set('value', me._layer.getVisible()); + this.checkBox.on("change", function(value) { + me._changed(value); + }); + }, + + _changed : function(visible) { + this._layer.setVisible(visible); + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/LayerRadioButton.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/LayerRadioButton.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,50 @@ +define([ + "dojo/_base/declare", + "dijit/_WidgetBase", + "dijit/_TemplatedMixin", + "dijit/_WidgetsInTemplateMixin", + "dojo/text!./resources/LayerRadioButtonTemplate.html", + "dijit/form/RadioButton" ], function(declare, _WidgetBase, _TemplatedMixin, + _WidgetsInTemplateMixin, templateString) { + return declare([ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin ], { + templateString : templateString, + + labelNode : null, + radioButton : null, + + label : "", + _setLabelAttr : { + node : "labelNode", + type : "innerHTML" + }, + + name : "layers", + + _layer : null, + + constructor : function(options) { + options = options || {}; + + if (!options.layer) + throw new Error("The layer is required"); + + this._layer = options.layer; + this.label = options.layer.get("label") || "unnamed"; + }, + + postCreate : function() { + var me = this; + me.inherited(arguments); + + me.radioButton.set('name', me.name); + me.radioButton.set('value', me._layer.getVisible()); + this.radioButton.on("change", function(value) { + me._changed(value); + }); + }, + + _changed : function(visible) { + this._layer.setVisible(visible); + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/LayerSwitcher.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/LayerSwitcher.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,81 @@ +define([ + "dojo/_base/declare", + "require", + "dijit/_WidgetBase", + "dijit/_TemplatedMixin", + "dijit/_WidgetsInTemplateMixin", + "dojo/text!./resources/LayerSwitcherTemplate.html", + "./LayerCheckBox", + "./LayerRadioButton", + "app/view/Container" ], + +function(declare, require, _WidgetBase, _TemplatedMixin, + _WidgetsInTemplateMixin, templateString, LayerCheckBox, LayerRadioButton) { + + return declare([ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin ], { + templateString : templateString, + requireScope : require, + _layers : null, + _map : null, + + infoLayersLabel : "Layers", + _setInfoLayersLabelAttr : { + node : "infoLayersLabelNode", + type : "innerHTML" + }, + + baseLayersLabel : "Base", + _setBaseLayersLabelAttr : { + node : "baseLayersLabelNode", + type : "innerHTML" + }, + + constructor : function(options) { + options = options || {}; + + if (!options.map) + throw new Error("The map is required"); + + this._map = options.map; + + if (options.layers && options.layers instanceof Array) + this._layers = options.layers; + else + this._layers = []; + + // this.baseLayersLabel = "Base"; + + }, + + postCreate : function() { + this.inherited(arguments); + + var pending = []; + + for ( var i in this._layers) { + if (this._layers[i].get("layerType") != "base") + pending.push(this._layers[i]); + else + this._addLayer(this._layers[i]); + } + + for ( var i in pending) + this._addLayer(pending[i]); + }, + + _addLayer : function(layer) { + this._map.addLayer(layer); + + if (layer.get("layerType") === "base") { + this.baseLayersContainer.addChild(new LayerRadioButton({ + layer : layer + })); + } else { + this.infoLayersContainer.addChild(new LayerCheckBox({ + layer : layer + })); + } + }, + + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/Map.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/Map.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,176 @@ +define([ + "dijit/registry", + "dojo/_base/declare", + "dijit/_WidgetBase", + "dojo/dom-construct", + "./PopupContainer", + "dojo/_base/array", + "ol", + "ol3/listen", + "dojo/Deferred", + "implab/safe" +], function (registry, declare, _WidgetBase, dom, PopupContainer, array, ol, listen, Deferred, safe) { + + return declare([_WidgetBase], { + popupOverlays: null, + olMap: null, + + _pending: null, + + constructor: function () { + this._pending = {}; + }, + + buildRendering: function () { + this.domNode = dom.create("div"); + }, + + postCreate: function () { + this.inherited(arguments); + this.popupOverlays = {}; + this.olMap = new ol.Map({ + target: this.domNode, + layers: this.layers, + view: this.view, + controls: this.controls || [], + }); + }, + + getProjection : function() { + return this.view.getProjection(); + }, + + addInteraction: function (value) { + this.olMap.addInteraction(value); + }, + + addLayer: function (layer) { + if (layer) { + if (layer.get("layerType") == "base") + this.olMap.getLayers().insertAt(0, layer); + else + this.olMap.addLayer(layer); + } + }, + + removeLayer: function(layer) { + this.olMap.removeLayer(layer); + }, + + startup: function () { + this.inherited(arguments); + + this.olMap.updateSize(); + }, + + showPopup: function (contentWidget, position, opts) { + // Скрыть popups указанной в opts.role роли, если (opts.hint == + // "replace") + // Если не задан opts или opta.hint скрывать все popup + + var me = this; + + if ((!opts) || (!opts.hint)) { + this.closeAllPopups(); + } else if ((opts.hint) && (opts.hint == "replace")) { + if (opts.role) { + this.closePopupsByRole(opts.role); + } else { + this.closeAllPopups(); + } + } + var overlay = new ol.Overlay({}); + + if (opts && (opts.role)) { + if (this.popupOverlays[opts.role]) { + this.popupOverlays[opts.role].push(overlay); + } else { + this.popupOverlays[opts.role] = [overlay]; + } + } + + // Отображение popUp start + this.olMap.addOverlay(overlay); + var popup = new PopupContainer({ + overlay: overlay, + map: this.olMap, + onClose: function () { + // registry.byNode(overlay.getElement()).destroyRecursive(); + array.forEach(me.popupOverlays[opts.role], function (o) { + if (o === overlay) { + var index = me.popupOverlays[opts.role].indexOf(o); + if (index > -1) { + me.popupOverlays[opts.role].splice(index, 1); + } + } + }); + } + }); + overlay.setElement(popup.domNode); + popup.show(contentWidget); + overlay.setPosition(position); + popup.hideOverlay(); + // end + return popup; + }, + + closeAllPopups: function () { + var overlays = this.olMap.getOverlays(); + overlays.forEach(function (elenemt, index) { + registry.byNode(elenemt.getElement()).destroyRecursive(); + }, this); + this.popupOverlays = {}; + }, + + closePopupsByRole: function (role) { + if (this.popupOverlays[role]) { + array.forEach(this.popupOverlays[role], function (overlay) { + registry.byNode(overlay.getElement()).destroyRecursive(); + }); + this.popupOverlays[role] = []; + } + }, + + /** + * Подписывается на событие карты + * + * @param {String} + * name Имя события + * @param {function(evt)} + * filter Фильтр того, что событие нужное + * + * @returns {ol.ObjectEvent | ol.MapBroeserEvent | ol.MapEvent} Событие + * на которое подписались. + */ + awaitMapEvent: function (name, filter) { + safe.argumentNotEmptyString(name, "name"); + var map = this.olMap, + handle, d, me = this; + + if (me._pending[name]) + throw new Error("An event is already pending: " + name); + + me._pending[name] = d = new Deferred(function () { + handle.remove(); + }); + + handle = listen.once(map, name, function (evt) { + if (!filter || filter(evt)) + d.resolve(evt); + }); + + return d.then(function (evt) { + delete me._pending[name]; + return evt; + }, function (err) { + delete me._pending[name]; + throw err; + }); + }, + + cancelPendingEvents: function () { + for (var name in this._pending) + this._pending[name].cancel(); + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/MeasureToolBase.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/MeasureToolBase.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,181 @@ +define([ + "dojo/_base/declare", + "implab/safe", + "ol", + "./listen", + "./_ToolBase", + "dojo/dom-construct", + "dojo/dom-class" +], function (declare, safe, ol, listen, _ToolBase, dconstruct, dclass) { + return declare([_ToolBase], { + _draw: null, + + drawStyle: new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)' + }), + stroke: new ol.style.Stroke({ + color: 'rgba(230, 126, 34, 0.7)', + lineDash: [10, 10], + width: 2 + }), + image: new ol.style.Circle({ + radius: 5, + stroke: new ol.style.Stroke({ + color: 'rgba(0, 0, 0, 0.7)' + }), + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)' + }) + }) + }), + + vectorStyle: new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)' + }), + stroke: new ol.style.Stroke({ + color: '#ffcc33', + width: 2 + }), + image: new ol.style.Circle({ + radius: 7, + fill: new ol.style.Fill({ + color: '#ffcc33' + }) + }) + }), + + _map: null, + + _olMap: null, + + _measureTooltipElement: null, + /** + * Overlay to show the measurement. + * + * @type {ol.Overlay} + */ + _measureTooltip: null, + + _pointermoveKey: null, + + _sketch: null, + + _overlays: null, + + _vector: null, + + wgs84Sphere: new ol.Sphere(6378137), + + constructor: function (options) { + safe.argumentNotNull(options, "options"); + safe.argumentNotNull(options.map, "map"); + + this._map = options.map; + this._olMap = options.map.olMap; + this._overlays = []; + }, + + init: function () { + if (this._draw) + return; + + var source = new ol.source.Vector(); + + this._vector = new ol.layer.Vector({ + source: source, + style: this.vectorStyle + }); + this._map.addLayer(this._vector); + + this._draw = this._createDraw(source); + this._draw.on('drawstart', this._onDrawStart, this); + this._draw.on('drawend', this._onDrawEnd, this); + + }, + + onActivating: function () { + this.init(); + + this._pointermoveKey = listen(this._olMap, 'pointermove', safe.delegate(this, "_onPointerMove")); + this._olMap.addInteraction(this._draw); + + return this.inherited(arguments); + }, + + onDeactivating: function () { + // отключаем рисование и получение сообщений + if (this._pointermoveKey) + this._pointermoveKey.remove(); + this._olMap.removeInteraction(this._draw); + + // если был активен инструмент + if (this._sketch) { + // убиваем подсказку и сбрасываем текущее рисование + this._sketch = null; + this._measureTooltipElement = null; + this._olMap.removeOverlay(this._measureTooltip); + } + + return this.inherited(arguments); + }, + + clear: function () { + var me = this; + me.log("clear"); + if (me._vector) { + me._vector.getSource().clear(); + me._overlays.forEach(function (x) { + me._olMap.removeOverlay(x); + }); + } + }, + + _createMeasureTooltip: function () { + this._measureTooltipElement = dconstruct.create("div", { + "class": 'tooltip poisk-measure-tooltip' + }); + this._measureTooltip = new ol.Overlay({ + element: this._measureTooltipElement, + offset: [0, -15], + positioning: 'bottom-center' + }); + this._olMap.addOverlay(this._measureTooltip); + + }, + + _onDrawStart: function (evt) { + this._sketch = evt.feature; + this._createMeasureTooltip(); + }, + + _onDrawEnd: function (evt) { + + this._measureTooltip.setOffset([0, -7]); + + dclass.remove(this._measureTooltipElement, "tooltip"); + dclass.add(this._measureTooltipElement, "tooltip-static"); + + this._overlays.push(this._measureTooltip); + + this._sketch = null; + this._measureTooltip = null; + this._measureTooltipElement = null; + }, + + _onPointerMove: function (evt) { + if (this._sketch && !evt.dragging) { + this._measureTooltip.setPosition(evt.coordinate); + this._measureTooltipElement.innerHTML = this._formatTooltip( + this._sketch, + this._olMap.getView().getProjection()); + } + }, + + _formatTooltip: function (sketch, proj) { + + } + }); + +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/OSMSource.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/OSMSource.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,3 @@ +define(["ol"], function(ol) { + return ol.source.OSM; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/OlTool.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/OlTool.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,21 @@ +define(["dojo/_base/declare", "dojo/_base/lang", "implab/safe", "dojo/dom-class", "dojo/dom-construct", "dijit/_TemplatedMixin", "dijit/_WidgetBase"], + function (declare, lang, safe, domClass, domConstruct, _TemplatedMixin, _WidgetBase) { + return declare([_WidgetBase, _TemplatedMixin], { + map : null, + control : null, + elementName : "div", + + constructor: function () { + lang.mixin(this, arguments[0]); + safe.argumentNotNull(this.map, "map"); + safe.argumentNotNull(this.control, "control"); + }, + + buildRendering : function() { + this.domNode = domConstruct.create(this.elementName); + domClass.add(this.domNode, this.baseClass); + this.control.setTarget(this.domNode); + this.control.setMap(this.map.olMap || this.map); + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/PopupContainer.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/PopupContainer.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,60 @@ +define([ + "dijit/_WidgetBase", + "dijit/_TemplatedMixin", + "dijit/_WidgetsInTemplateMixin", + "dijit/_Container", + "dojo/_base/declare", + "dojo/Evented", + "dojo/dom-class", + "dojo/on", + "dojo/text!./resources/PopupContainerTemplate.html", + "ol" +], + function (_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _Container, declare, Evented, domClass, on, templateString, ol) { + return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _Container/*, Evented*/], { + + templateString: templateString, + + overlay: null, + + map : null, + + constructor: function (options) { + options = options || {}; + }, + + postCreate: function () { + var me = this; + this.inherited(arguments); + on(this.popupCloser, "click", function () { + me.destroyRecursive(); + me.onClose(); + }); + }, + + show: function (widget, opts) { + opts = opts || "only"; + if (widget) { + widget.placeAt(this.popupContent, opts); + } + }, + + hideOverlay: function () { + domClass.add(this.popupOverlay, "hidden") + }, + + showOverlay: function () { + domClass.remove(this.popupOverlay, "hidden") + }, + + destroy : function() { + this.map.removeOverlay(this.overlay); + this.inherited(arguments); + }, + + onClose: function () { + this.emit("close"); + } + + }); + }); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/SquareMeasureTool.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/SquareMeasureTool.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,61 @@ +define([ + "dojo/_base/declare", + "implab/safe", + "./MeasureToolBase", + "implab/text/format", + "dojo/i18n!./format/nls/units", + "ol" ], + +function(declare, safe, MeasureToolBase, format, units, ol) { + return declare([ MeasureToolBase ], { + + isGeodesic : true, + + units : 'metric', + + constructor : function(opts) { + if (opts) + safe.mixin(this,opts,["isGeodesic", "units"]); + }, + + _createDraw : function(source) { + return new ol.interaction.Draw({ + source : source, + type : "Polygon", + style : this.drawStyle + }); + }, + + _formatTooltip : function(sketch, proj) { + var area; + if (this.isGeodesic) { + var geom = sketch.getGeometry().clone().transform(proj, 'EPSG:4326'); + var coordinates = geom.getLinearRing(0).getCoordinates(); + area = Math.abs(this.wgs84Sphere.geodesicArea(coordinates)); + } else { + area = sketch.getGeometry().getArea(); + } + + var mpu, unitName; + switch (this.units) { + case "nautical": + mpu = 1852*1852; + unitName = units.nmiles2; + break; + default: + mpu = 1852*1852; + unitName = units.kilometers2; + } + + if (area > mpu/10) { + return format( + "{0:#0.##} {1}", + area / mpu, + unitName); + } else { + return format("{0:#0.##} {1}", area, units.meters2); + } + } + + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/TileLayer.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/TileLayer.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,3 @@ +define(["ol"], function(ol) { + return ol.layer.Tile; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/TileWMSSource.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/TileWMSSource.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,3 @@ +define(["ol"], function(ol) { + return ol.source.TileWMS; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/ToolBoxController.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/ToolBoxController.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,43 @@ +define([ + "dojo/_base/declare", + "implab/safe", + "implab/components/ActivationController", + "./ToolType" ], + +function(declare, safe, ActivationController, ToolType) { + return declare([ ActivationController ], { + _stack : null, + _tools : null, + + constructor : function() { + this._stack = new Array(); + this._tools = new Array(); + }, + + activate : function(tool) { + safe.argumentNotNull(tool, "tool"); + + var me = this, current = me.getCurrent(); + + return this.inherited(arguments).then(function(success) { + if (success) { + if (tool.toolType == ToolType.Oneshot && current) + me._stack.push(current); + else + me._stack = []; + } + return success; + }); + }, + + deactivate : function() { + var me = this; + return me.inherited(arguments).then(function(success) { + if (success && me._stack.length) + return me.activate(me._stack.pop()); + + return success; + }); + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/ToolType.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/ToolType.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,6 @@ +define([], function(){ + return { + Activatable : 1, + Oneshot : 2 + }; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/VectorLayer.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/VectorLayer.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,68 @@ +define([ + "implab/guard", + "implab/text/template-compile", + "dojo/_base/declare", + "dojo/_base/lang", + "dojo/Deferred", + "ol"], + function (guard, compile, declare, lang, Deferred, ol) { + return declare([ol.layer.Vector], { + + map: null, + + _olMap: null, + + name: null, + + displayName: null, + + identifyResultTemplate: null, + + identifyCompiledTemplate:null, + + searchResultTemplate: null, + + searchCompiledTemplate: null, + + constructor: function () { + lang.mixin(this, arguments[0]); + this._olMap = this.map.olMap; + var identifyCompiledTemplate = null, searchCompiledTemplate = null; + if (this.identifyResultTemplate) { + this.identifyCompiledTemplate = compile(this.identifyResultTemplate); + } + if (this.searchResultTemplate) { + this.searchCompiledTemplate = compile(this.searchResultTemplate); + } + }, + + /** Возвращает массив строк, каждая строка - результат поиска приведенный к шаблонному виду + @options {Object} + @str {String} поисковая строка + @bbox {Object} bound box, в рамках которого осуществлять поиск + */ + getSearchResult: function (options) { + return null; + }, + + _getIdentifyResult: function (options) { + var me = this; + var features = []; + //TODO: добавить фильтр по layer равный ему самому + this._olMap.forEachFeatureAtPixel(options.pixel, function (feature, layer) { + features.push({ feature: feature, layer: layer }); + }, null, function (layer) { + return layer == me; + }); + console.log(features); + return features; + }, + /** Возвращает массив строк, каждая строка - результат идентификации приведенный к шаблонному виду + @options {Object} + @coordinates {Array} массив описывающий координаты точки идентификации + */ + getIdentifyResult: function (coordinates) { + return guard(this, "_getIdentifyResult", [coordinates]); + } + }); + }) \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/VectorStore.js --- /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 + * + *
+                 * {
+                 *     extent : ol3.Extent,
+                 * }
+                 * 
+ */ + 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 diff -r 37e9e6bbe87a -r 8705103f074f src/djol/VectorStoreQuery.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/VectorStoreQuery.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,67 @@ +define([ "ol" ], function(ol) { + + function buildFilter(filter) { + if (filter instanceof Function) + return filter; + if (filter) { + var match = function(str) { + return { + test : function(x) { + if (x === null || x === undefined) + return false; + return x.toString().startsWith(str); + } + }; + }; + + for ( var p in filter) { + if (typeof (filter[p]) == "string" && filter[p].endsWith("*")) + filter[p] = match(filter[p].substr(0, filter[p].length)); + } + return function(ft) { + for ( var p in filter) { + if (filter[p] && filter[p].test ? !filter[p] + .test(ft.get(p)) : ft.get(p) != filter[p]) + return false; + } + return true; + }; + } + throw new Error("Unsupported filter"); + } + + /** + * @constructor + * @example + * + *
+     * var store = new VectorStore({
+     *     source : vectorSource
+     * });
+     * 
+     * var req = new VectorStoreQuery({
+     *     city : "Moscow"
+     * }, [ 30, 50, 40, 60 ]);
+     * 
+     * store.query(req).then(showResults);
+     * 
+ */ + return function(filter, extent) { + var match = filter && buildFilter(filter); + + var query = function(ft) { + if (extent) { + var g = gt.getGeometry(); + if (!g || !ol.extent.intersects(extent, g.getExtent())) + return false; + } + + return !match || match(ft); + }; + + query.extent = extent; + query.predicate = match; + + return query; + }; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/WFSSource.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/WFSSource.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,112 @@ +define([ "ol", "dojo/request", "dojo/_base/array", "implab/safe"], + +function(ol, request, array, safe) { + return function(wfs, featurePrefix, featureType, featureNS, queryArgs) { + if (arguments.length == 1) { + featurePrefix = wfs.featurePrefix; + featureType = wfs.featureType; + featureNS = wfs.featureNS; + wfs = wfs.wfsURL; + queryArgs = wfs.queryArgs; + } + + safe.argumentNotNull(wfs, "wfsURL"); + safe.argumentNotEmpty(featurePrefix, "featurePrefix"); + safe.argumentNotEmpty(featureNS, "featureNS"); + safe.argumentNotEmpty(featureType, "featureType"); + + var format = new ol.format.WFS({ + featureNS : featureNS, + featureType : featureType + }); + + var layerName = featurePrefix + ":" + featureType; + + function loader(extent, resolution, projection) { + var query = { + service : 'WFS', + version : '1.1.0', + request : 'GetFeature', + typename : layerName, + srsname : projection.getCode() + }; + safe.mixin(query, queryArgs); + + if (extent && isFinite(extent[0])) + query.bbox = extent.join(',') + "," + projection.getCode(); + + return request(wfs, { + query : query, + handleAs : 'xml' + }).then(function(data) { + // в загрузчике нельзя вызывать метод source.clear() поскольку + // это приводит к рекурсии + var features = format.readFeatures(data); + + var map = {}, del = [], add = []; + + array.forEach(features, function(x) { + // HACK исправляем идентификаторы, чтобы они совпадали с + // реальными + + var id = x.get("id"); + if (id) + x.setId(id); + else + id = x.getId(); + + map[id] = x; + + // нужно проверить, была ли фича на карте + var prev = source.getFeatureById(id); + if (prev) { + // если да, то обновить ее. + var data = x.getProperties(); + prev.setProperties(data); + } else { + // иначе добавить + add.push(x); + } + }); + + source.forEachFeatureInExtent(extent, function(x) { + if (!(x.getId() in map)) + del.push(x); + }); + + source.addFeatures(add); + + array.forEach(del, function(x) { + source.removeFeature(x); + }); + + //revision = revision + 1; + + source.set("revision", ++revision); + + }); + } + + var cls = ol.source.ServerVector || ol.source.Vector; + var revision = 0; + var source = new cls({ + loader : loader, + //revision: revision + wrapX : false + // , + // strategy : options.strategy || ol.loadingstrategy.all, + // projection : options.projection + }); + source.set("revision", revision); + source.reload = function(extent,resolution, projection, q) { + if (arguments.length >= 4) + queryArgs = q; + if (!extent) + extent = [-Infinity, -Infinity, Infinity, Infinity]; + return loader(extent,resolution,projection); + }; + + console.log(wfs, layerName); + return source; + }; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/_OneshotTool.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/_OneshotTool.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,65 @@ +define([ "dojo/_base/declare", "implab/safe", "implab/guard", "ol3/_ToolBase", "ol3/ToolType" ], + +function(declare, safe, guard, _ToolBase, ToolType) { + return declare([ _ToolBase ], { + _pending : null, + + _lastResult : null, + + toolType : ToolType.Oneshot, + + invoke : function() { + }, + + onActivating : function() { + var me = this; + + // start the operation + me._lastResult = me._pending = guard(me,"invoke"); + + return this.inherited(arguments); + }, + + onActivated : function() { + var me = this; + + // fire the activate event + this.inherited(arguments); + + me._pending.then(function() { + if (me._pending) { + me.log("Operation finished, deactivating."); + me._pending = null; + me.deactivate(); + } + }, function(ex) { + if (me._pending) { + me.error("Operation failed, deactivating: {0}", ex); + me._pending = null; + me.deactivate(); + } + }); + }, + + onDeactivated : function() { + var d = this._pending; + if (d) { + this.log("Cancelling pending operation"); + this._pending = null; + d.cancel(); + } + + return this.inherited(arguments); + }, + + run : function() { + var me = this; + + return me.activate().then(function(success) { + if (success) + return me._lastResult; + throw new Error("Operation declined"); + }); + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/_ToolBase.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/_ToolBase.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,46 @@ +define([ + "dojo/_base/declare", + "dojo/when", + "implab/safe", + "implab/guard", + "implab/components/_ActivatableMixin", + "implab/log/_LogMixin", + "dojo/Evented", + "./ToolType" ], + +function(declare, when, safe, guard, _ActivatableMixin, _LogMixin, Evented, ToolType) { + return declare([ _ActivatableMixin, Evented ], { + toolType : ToolType.Activatable, + + module : null, + + constructor : function(opts) { + if (opts) { + if (opts.controller) + this.setController(opts.controller); + } + }, + + onActivating : function() { + var me = this, inherited = this.getInherited(arguments); + if (me.module && !me.module.isActive()) + return me.module.activate().then(function(active) { + return active ? inherited.apply(me) : false; + }); + else + return inherited.apply(me); + }, + + onActivated : function() { + this.emit("active", true); + }, + + onDeactivated : function() { + this.emit("active", false); + }, + + destroy : function() { + + } + }); +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/declare-style.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/declare-style.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,20 @@ +define(["dojo/_base/declare","implab/safe"],function(declare, safe){ + return function(base, proto){ + var cls = declare(base,proto); + + var factory = function() { + var me = this; + cls.apply(me,arguments); + var fn = function() { + return me.getFeatureStyle.apply(me,arguments); + }; + fn.style = me; + fn.styleFunction = fn; + return fn; + }; + + factory.styleClass = cls; + factory.prototype = cls.prototype; + return factory; + }; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/format/coords.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/format/coords.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,71 @@ +define( + [ "dojo/i18n!./nls/coords", "implab/text/format", "implab/safe" ], + + function(nls, format, safe) { + + var formatDMS = function(coord) { + return formatSD(coord, nls.dmsPattern); + }; + + var formatDM = function(coord) { + return formatSD(coord, nls.dmPattern); + }; + + var formatD = function(coord) { + return formatSD(coord, nls.dPattern); + }; + + /** + * pattern: + * + * {0} - signed floating point number - latitude + * + * {1} - positive floating point number - minutes part of latitude + * + * {2} - positive floating point number - seconds part of latitude + * + * {3} - localized hemisphere sign: north or south + * + * {4} - signed floating point number - longitude + * + * {5} - positive floating point number - minutes part of longitude + * + * {6} - positive floating point number - seconds part of longitude + * + * {7} - localized hemisphere sign: east or west + */ + var formatSD = function(coord, pattern) { + safe.argumentNotNull(coord, "coord"); + if (!pattern) + pattern = nls.sdPattern; + var x = (coord[0] % 360 + 540) % 360 - 180, y = (coord[1] % 180 + 270) % 180 - 90; + + return format(pattern, y, Math.abs((y * 60) % 60), Math + .abs((y * 3600) % 60), y >= 0 ? nls.north : nls.south, x, Math + .abs((x * 60) % 60), Math.abs((x * 3600) % 60), x >= 0 + ? nls.east + : nls.west); + }; + + var cls = function(fmt) { + switch (fmt) { + case "DMS": + return formatDMS; + case "DM": + return formatDM; + case "D": + return formatD; + case "SD": + return formatSD; + default: + if (!fmt) + return formatSD; + else + return function(coord) { + return formatSD(coord, fmt); + } + } + }; + + return cls; + }); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/format/nls/coords.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/format/nls/coords.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,14 @@ +define({ + root : { + // lat lon + dmsPattern : "{0:!00;00}\u00b0{1:!00}\u2032{2:00}\u2033{3} {4:!000;000}\u00b0{5:!00}\u2032{6:00}\u2033{7}", + dmPattern : "{0:!00;00}\u00b0{1:00.0000}\u2032{3} {4:000;000}\u00b0{5:!00.0000}\u2032{7}", + dPattern : "{0:00.000000;00.000000}\u00b0{3} {4:000.000000;000.000000}\u00b0{7}", + sdPattern : "{0:#0.000000}, {4:#0.000000}", + north : "N", + south : "S", + west : "W", + east : "E" + }, + ru : true +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/format/nls/ru/coords.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/format/nls/ru/coords.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,6 @@ +define({ + north : "С", + south : "Ю", + west : "З", + east : "В" +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/format/nls/ru/units.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/format/nls/ru/units.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,11 @@ +define({ + kmph : "км/ч", + mps : "м/с", + knots : "уз", + meters : "м", + kilometers : "км", + meters2 : "м2", + kilometers2 : "км2", + nmiles : "миль", + nmiles2 : "миль2" +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/format/nls/units.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/format/nls/units.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,14 @@ +define({ + root : { + kmph: "km/h", + mps: "m/s", + knots : "kn", + meters : "m", + kilometers : "km", + meters2 : "m2", + kilometers2 : "m2", + nmiles : "nmi", + nmiles2 : "nmi2" + }, + ru : true +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/interaction/FeatureDrag.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/interaction/FeatureDrag.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,123 @@ +define([ "dojo/_base/declare", "ol", "dojo/Evented" ], function(declare, ol, + Evented) { + + var peekFirstFeature = function(map, coordinate, pixel) { + return map.forEachFeatureAtPixel(function(ft, layer) { + return ft; + }); + }; + + var cls = declare([ ol.interaction.Pointer ], { + "-chains-" : { + constructor : "manual" + }, + + _peek : null, + + _feature : null, + + _coordinate : null, + + cursor : "pointer", + + _oldCursor : undefined, + + /** + * Создает новый объект + * + * @param {Object} + * opts опции + * @param {Function} + * opts.peek Функция выбора фичи для перетаскивания + * function(map,coordinate,pixel), возвращает фичу + * @param {String} + * opts.cursor css курсор который будет использован при + * наведении и перетаскивании фичи + * + */ + constructor : function(opts) { + + ol.interaction.Pointer.apply(this, [{ + handleDownEvent : this.handleDownEvent, + handleDragEvent : this.handleDragEvent, + handleMoveEvent : this.handleMoveEvent, + handleUpEvent : this.handleUpEvent + }]); + Evented.apply(this); + + if (opts) { + if (opts.peek) { + this._peek = opts.peek; + } else { + this._peek = peekFirstFeature; + } + if ("cursor" in opts) + this.cursor = opts.cursor; + } + }, + + handleDownEvent : function(evt) { + var c = evt.coordinate; + + var ft = this._peek(evt.map, c, evt.pixel); + + if (ft) { + this._feature = ft; + this._coordinate = c; + this._emit("dragbegin", { feature : ft }); + return true; + } + + return false; + }, + + handleDragEvent : function(evt) { + var c1 = this._coordinate, c2 = evt.coordinate; + + var dx = c2[0] - c1[0]; + var dy = c2[1] - c1[1]; + + this._emit("dragging", { feature : this._feature, fromCoord : c1, toCoord : c2 }); + + this._feature.getGeometry().translate(dx, dy); + + this._coordinate = c2; + }, + + handleUpEvent : function(evt) { + if (this._feature) + this._emit("dragend", { feature : this._feature }); + + this._feature = null; + this._coordinate = null; + return false; + }, + + handleMoveEvent : function(evt) { + if (this.cursor) { + var ft = this._feature || this._peek(evt.map, evt.coordinate , evt.pixel); + + var element = evt.map.getTargetElement(); + if (ft) { + if (element.style.cursor != this.cursor) { + this._oldCursor = element.style.cursor; + element.style.cursor = this.cursor; + } + } else if (this._oldCursor !== undefined) { + element.style.cursor = this._oldCursor; + this._oldCursor = undefined; + } + } + }, + + _emit : function(name, data) { + var evt = new ol.source.VectorEvent(name,this); + + for(var p in data) + evt[p] = data[p]; + this.dispatchEvent(evt); + } + }); + + return cls; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/listen.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/listen.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,22 @@ +define(["ol"], function(ol) { + + var listen = function(target, event, callback) { + var key = target.on(event, callback); + return { + remove : function() { + ol.Observable.unByKey(key); + } + }; + }; + + listen.once = function(target, event, callback) { + var key = target.once(event, callback); + return { + remove : function() { + ol.Observable.unByKey(key); + } + }; + }; + + return listen; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/main.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/main.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,6 @@ +define([ "ol" ], function(ol) { + // вспомогательный класс для получения ol в виде зависимости + return function() { + return ol; + }; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/ol-stub.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/ol-stub.js Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,4 @@ +var ol; +define([], function() { + return ol; +}); \ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/resources/LayerCheckBoxTemplate.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/resources/LayerCheckBoxTemplate.html Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,4 @@ +
+ +
\ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/resources/LayerRadioButtonTemplate.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/resources/LayerRadioButtonTemplate.html Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,5 @@ +
+ +
\ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/resources/LayerSwitcherTemplate.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/resources/LayerSwitcherTemplate.html Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,6 @@ +
+

+
+

+
+
\ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/resources/PopupContainerTemplate.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/resources/PopupContainerTemplate.html Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,8 @@ +
+ +
+ +
\ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/djol/resources/mapToolCheckBox.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/djol/resources/mapToolCheckBox.html Mon Aug 21 18:03:00 2017 +0300 @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff -r 37e9e6bbe87a -r 8705103f074f src/implab/data/ObjectStore.js --- a/src/implab/data/ObjectStore.js Mon Jun 26 13:27:27 2017 +0300 +++ b/src/implab/data/ObjectStore.js Mon Aug 21 18:03:00 2017 +0300 @@ -2,10 +2,10 @@ "../safe", "dojo/when", "dojo/Deferred", "dojo/store/util/QueryResults" ], function(declare, lang, array, safe, when, Deferred, QueryResults) { /** - * @module core/data/RestStore + * @module implab/data/RestStore * * Реализует шаблон репозитария dojo/store над уже имеющимся хранилищем. При получении и - * отправке данных в нижележащие хранилище используется core/data/MapSchema для преобразования + * отправке данных в нижележащие хранилище используется implab/data/MapSchema для преобразования * данных. */ return declare(null, { diff -r 37e9e6bbe87a -r 8705103f074f src/implab/data/RestStore.js --- a/src/implab/data/RestStore.js Mon Jun 26 13:27:27 2017 +0300 +++ b/src/implab/data/RestStore.js Mon Aug 21 18:03:00 2017 +0300 @@ -2,10 +2,10 @@ "../safe", "dojo/when", "dojo/Deferred", "dojo/store/util/QueryResults" ], function(declare, lang, array, safe, when, Deferred, QueryResults) { /** - * @module core/data/RestStore + * @module implab/data/RestStore * * Реализует шаблон репозитария dojo/store над уже имеющимся хранилищем. При получении и - * отправке данных в нижележащие хранилище используется core/data/MapSchema для преобразования + * отправке данных в нижележащие хранилище используется implab/data/MapSchema для преобразования * данных. */ return declare(null, { diff -r 37e9e6bbe87a -r 8705103f074f src/implab/safe.js --- a/src/implab/safe.js Mon Jun 26 13:27:27 2017 +0300 +++ b/src/implab/safe.js Mon Aug 21 18:03:00 2017 +0300 @@ -143,7 +143,7 @@ * @param{Function|String} fn [Required] Function wich will be wrapped. */ async: function (fn, thisArg) { - if (arguments.length == 2) + if (arguments.length == 2 && !(fn instanceof Function)) fn = thisArg[fn]; if (fn == null) diff -r 37e9e6bbe87a -r 8705103f074f src/implab/text/template-compile.js --- a/src/implab/text/template-compile.js Mon Jun 26 13:27:27 2017 +0300 +++ b/src/implab/text/template-compile.js Mon Aug 21 18:03:00 2017 +0300 @@ -44,7 +44,7 @@ }, function(err) { require.signal("error", [ { error : err, - src : 'implab/template-compile' + src : 'implab/text/template-compile' } ]); }); }