diff --git a/addon/components/base-vector-layer.js b/addon/components/base-vector-layer.js index 218466220..9976b0d67 100644 --- a/addon/components/base-vector-layer.js +++ b/addon/components/base-vector-layer.js @@ -1317,5 +1317,32 @@ export default BaseLayer.extend(layerLabel, { } else { return geoJSONLayer.geometry.coordinates; } + }, + + _boundsCrs(leafletObject) { + let leafletMap = this.get('leafletMap'); + let boundsMap = leafletMap.getBounds(); + if (boundsMap && leafletObject.options && leafletObject.options.crs && leafletObject.options.crs.bounds) { + let crsBounds = leafletObject.options.crs.bounds; + if (boundsMap._northEast.lat > crsBounds.max.x) { + boundsMap._northEast.lat = crsBounds.max.x; + } + + if (boundsMap._northEast.lng > crsBounds.max.y) { + boundsMap._northEast.lng = crsBounds.max.y; + } + + if ((boundsMap._southWest.lat < 0 && boundsMap._southWest.lat < crsBounds.min.x) || + (boundsMap._southWest.lat > 0 && boundsMap._southWest.lat > crsBounds.min.x)) { + boundsMap._southWest.lat = crsBounds.min.x; + } + + if ((boundsMap._southWest.lng < 0 && boundsMap._southWest.lng < crsBounds.min.y) || + (boundsMap._southWest.lng > 0 && boundsMap._southWest.lng > crsBounds.min.y)) { + boundsMap._southWest.lng = crsBounds.min.y; + } + } + + return boundsMap; } }); diff --git a/addon/components/feature-result-item.js b/addon/components/feature-result-item.js index d4b628432..2ca338b23 100644 --- a/addon/components/feature-result-item.js +++ b/addon/components/feature-result-item.js @@ -8,13 +8,14 @@ import { translationMacro as t } from 'ember-i18n'; import openCloseSubmenu from 'ember-flexberry-gis/utils/open-close-sub-menu'; import { zoomToBounds } from '../utils/zoom-to-bounds'; import ResultFeatureInitializer from '../mixins/result-feature-initializer'; +import SlotsMixin from 'ember-block-slots'; /** Component for display GeoJSON feature object details @class FeatureResultItemComponent @extends Ember.Component */ -export default Ember.Component.extend(ResultFeatureInitializer, { +export default Ember.Component.extend(SlotsMixin, ResultFeatureInitializer, { /** Service for managing map API. @@ -600,15 +601,6 @@ export default Ember.Component.extend(ResultFeatureInitializer, { this.sendAction('findIntersection', this.get('feature')); }, - /** - * Action for search satellites - * @method actions.searchSatellites - */ - searchSatellites() { - this.set('isSubmenu', false); - this.sendAction('searchSatellites', this.get('feature')); - }, - /** Add feature to favorites list Action is sended to layer-result-list. diff --git a/addon/components/flexberry-edit-layer-feature.js b/addon/components/flexberry-edit-layer-feature.js index b87fc08f6..d82b44f86 100644 --- a/addon/components/flexberry-edit-layer-feature.js +++ b/addon/components/flexberry-edit-layer-feature.js @@ -4,7 +4,6 @@ import SnapDrawMixin from '../mixins/snap-draw'; import EditFeatureMixin from '../mixins/edit-feature'; import LeafletZoomToFeatureMixin from '../mixins/leaflet-zoom-to-feature'; import { translationMacro as t } from 'ember-i18n'; -import { getLeafletCrs } from '../utils/leaflet-crs'; import { addAlpha, splitColor } from '../utils/leaflet-opacity'; export default Ember.Component.extend(SnapDrawMixin, LeafletZoomToFeatureMixin, EditFeatureMixin, { @@ -778,8 +777,10 @@ export default Ember.Component.extend(SnapDrawMixin, LeafletZoomToFeatureMixin, // Removing a layer from the map that was added for edit mode if (leafletMap.hasLayer(layer)) { - layer.setStyle(layer.defaultFeatureStyle); - layer.styleIsSet = layer.defaultSetStyle; + if (!this.get('isLayerCopy')) { + layer.setStyle(layer.defaultFeatureStyle); + layer.styleIsSet = layer.defaultSetStyle; + } if (this.get('isLayerCopy')) { leafletMap.removeLayer(layer); @@ -893,81 +894,6 @@ export default Ember.Component.extend(SnapDrawMixin, LeafletZoomToFeatureMixin, } }, - /** - Sends request to trancate GeoWebCache for layer by boundingBox. - - @method trancateGeoWebCache - @param {Object} leafletObject laeflet layer. - */ - trancateGeoWebCache(leafletObject) { - let layers = leafletObject.wmsParams.layers.split(); - let workspace; - let layer; - let geoWebCache; - if (layers.length === 2) { - workspace = layers[0]; - layer = layers[1]; - } else { - let urlSplit = leafletObject._url.split('/'); - let indexGeoserver = urlSplit.indexOf('geoserver'); - if (indexGeoserver > -1 && urlSplit.length === indexGeoserver + 3) { - workspace = urlSplit.at(indexGeoserver + 1); - } else { - console.error('Can\'t get workspace in geoserver'); - return; - } - - layer = layers[0]; - } - - if (!Ember.isBlank(leafletObject._url.match(new RegExp('(https?|ftp)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?')))) { - let indexGeoserver = leafletObject._url.indexOf('geoserver'); - if (indexGeoserver === -1) { - console.error('Can\'t get url geoserver'); - return; - } - - geoWebCache = leafletObject._url.slice(0, indexGeoserver + 10) + '/gwc/rest/seed/'; - } - - if (!Ember.isNone(geoWebCache)) { - let url = geoWebCache + workspace + ':' + layer; - let gridSetId = leafletObject.wmsParams.crs + '_' + leafletObject.wmsParams.width; - let leafletMap = this.get('leafletMap'); - let zoom = Math.trunc(leafletMap.getZoom()); - let zoomStart = zoom - 1 > 0 ? zoom - 1 : zoom; - let zoomStop = zoom + 1 < 20 ? zoom + 1 : zoom; - let styles = leafletObject.wmsParams.styles; - let parameterStyles = ''; - if (!Ember.isNone(styles)) { - parameterStyles = `parameter_STYLES=${workspace}:${styles}&`; - } - - let crsName = leafletObject.wmsParams.crs; - let crs; - if (!Ember.isNone(crsName)) { - crs = getLeafletCrs('{ "code": "' + crsName.toUpperCase() + '", "definition": "" }', this); - } - - let bounds = leafletMap.getBounds(); - let minXY = L.marker(bounds._southWest).toProjectedGeoJSON(crs); - let maxXY = L.marker(bounds._northEast).toProjectedGeoJSON(crs); - - Ember.$.ajax({ - method: 'POST', - url: url, - async: true, - data: `threadCount=01&type=truncate&gridSetId=${gridSetId}&tileFormat=image%2Fpng&zoomStart=${zoomStart}&zoomStop=${zoomStop}&` + - `${parameterStyles}minX=${minXY.geometry.coordinates[0]}&minY=${minXY.geometry.coordinates[1]}` + - `&maxX=${maxXY.geometry.coordinates[0]}&maxY=${maxXY.geometry.coordinates[1]}`, - contentType: 'text/html', - error: function(data) { - console.error(data); - } - }); - } - }, - actions: { blockForm(block) { @@ -1172,8 +1098,10 @@ export default Ember.Component.extend(SnapDrawMixin, LeafletZoomToFeatureMixin, leafletObject.editLayer(layer); if (leafletMap.hasLayer(layer)) { - layer.setStyle(layer.defaultFeatureStyle); - layer.styleIsSet = layer.defaultSetStyle; + if (!this.get('isLayerCopy')) { + layer.setStyle(layer.defaultFeatureStyle); + layer.styleIsSet = layer.defaultSetStyle; + } if (this.get('isLayerCopy')) { // Deleting a copy of an edited layer from the map @@ -1248,8 +1176,9 @@ export default Ember.Component.extend(SnapDrawMixin, LeafletZoomToFeatureMixin, this.set('mode', 'Saved'); let _leafletObjectFirst = this.get('layerModel.layerModel._leafletObjectFirst'); + let leafletMap = this.get('leafletMap'); if (!Ember.isNone(_leafletObjectFirst) && typeof _leafletObjectFirst.setParams === 'function') { - this.trancateGeoWebCache(_leafletObjectFirst); + this.trancateGeoWebCache(_leafletObjectFirst, leafletMap); _leafletObjectFirst.setParams({ fake: Date.now() }, false); } diff --git a/addon/components/flexberry-identify-file.js b/addon/components/flexberry-identify-file.js index 28f65bdc3..4a46da2e7 100644 --- a/addon/components/flexberry-identify-file.js +++ b/addon/components/flexberry-identify-file.js @@ -28,11 +28,26 @@ export default Ember.Component.extend(CheckFileMixin, { */ geometryField2: null, + /** + Necessity of geometry field names (one (with WKT geometry) or two (X,Y coordinates - points only)) + geometryField1 and geometryField2 + For .csv, .xls, .xlsx + */ needGeometryFieldName: false, - acceptFiles: null, + /** + Necessity of geometry type. For .gpx (it contains different types of data and can be transformed to different types of data) + */ + needGeometryType: false, + + /** + Necessity of "not auto" CRS + */ + needCRS: false, + + acceptFiles: '.zip,.GEOJSON,.gml,.xls,.xlsx,.csv,.xml,.gpx,.kml', - importErrorMessage: 'Загруженный файл не соответствует требованиям: ', + importErrorMessage: 'Загруженный файл не соответствует требованиям', emptyErrorMessage: 'Файл не содержит геометрических объектов', @@ -42,11 +57,10 @@ export default Ember.Component.extend(CheckFileMixin, { typeGeometryErrorMessage: 'Указанный тип геометрии противоречит объектам в файле', - warningMessageSRS: 'Укажите верную систему координат, указанную в загружаемом файле. ' + - 'При выборе ошибочной системы координат слой может некорректно отображаться на карте', - warningMessageEmptyGeometry: 'В файле обнаружены объекты без геометрии. Дальнейшая загрузка будет осуществлена без них', + warningMessageAutoCRS: 'У загруженного файла не определена система координат. Выберите систему координат из списка', + emptyGeometryField: 'Укажите название поля с геометрией в файле (WKT/X,Y)', /** @@ -67,18 +81,11 @@ export default Ember.Component.extend(CheckFileMixin, { }); }, - setAcceptFiles() { - if (Ember.isEmpty(this.get('acceptFiles'))) { - this.set('acceptFiles', '.zip,.GEOJSON,.gml,.xls,.xlsx,.csv,.xml,.gps,.kml'); - } - }, - didInsertElement() { this._super(...arguments); this.set('systemCoordinates', this.get('systemCoordinates') || availableCoordinateReferenceSystemsCodesWithCaptions(this)); this.set('coordinate', 'auto'); - this.setAcceptFiles(); this.send('clearFile'); }, @@ -121,7 +128,7 @@ export default Ember.Component.extend(CheckFileMixin, { @method fieldsSet */ - fieldsSet: Ember.observer('file', 'needGeometryFieldName', 'geometryField1', 'geometryField2', function() { + fieldsSet: Ember.observer('file', 'needGeometryFieldName', 'geometryField1', 'geometryField2', function () { let file = this.get('file'); if (this.get('needGeometryFieldName') && !Ember.isNone(file)) { let geometryField1 = this.get('geometryField1'); @@ -134,11 +141,11 @@ export default Ember.Component.extend(CheckFileMixin, { }), /** - Get headers fields from csv or xls file. + Get headers fields from csv or xls|xlsx file. - @method getFieldsFromCsv + @method getFields */ - getFieldsFromCsv() { + getFields() { this.set('_showError', false); let config = Ember.getOwner(this).resolveRegistration('config:environment'); let data = new FormData(); @@ -154,29 +161,27 @@ export default Ember.Component.extend(CheckFileMixin, { processData: false, }).done((response) => { if (response && response.length) { - const items = response.split(','); - this.set('_availableFields', Ember.A(items)); - this.set('needGeometryFieldName', true); + this.set('_availableFields', Ember.A(response)); } else { - this.set('_errorMessage', this.get('importErrorMessage') + this.get('emptyHeaderErrorMessage')); + this.set('_errorMessage', this.get('emptyHeaderErrorMessage')); this.set('_showError', true); - this.set('needGeometryFieldName', false); - this.set('needGeometryType', false); } }).fail(() => { let message = this.get('badFileMessage'); - this.set('_errorMessage', this.get('importErrorMessage') + message); + this.set('_errorMessage', message); this.set('_showError', true); - this.set('needGeometryFieldName', false); - this.set('needGeometryType', false); }); } }, actions: { - onCoordinateChange() { + clearCacheAndPreview() { this.set('_showError', false); this.clearAjax(); + if (this.get('filePreview')) { + this.get('mapApi').getFromApi('leafletMap').fire(`flexberry-map-loadfile${this.get('suffix')}:clear`); + this.set('filePreview', false); + } }, clearFile() { @@ -184,6 +189,7 @@ export default Ember.Component.extend(CheckFileMixin, { this.set('coordinate', 'auto'); this.set('needGeometryFieldName', false); this.set('needGeometryType', false); + this.set('needCRS', false); this.set('geometryField1', null); this.set('geometryField2', null); this.set('geometryFieldFile', null); @@ -201,19 +207,33 @@ export default Ember.Component.extend(CheckFileMixin, { this.$('.ui.button.remove').addClass('hidden'); }, + /** + * Выбор пользователем файла + */ clickFile(e) { let file = e.target.files[0]; + if (!file) { + return; + } + let fileName = file.name; - let ext = fileName.substring(fileName.indexOf('.'), fileName.length); + let ext = fileName.substring(fileName.lastIndexOf('.'), fileName.length).toLowerCase(); this.set('file', file); - if (ext.toLowerCase() === '.csv' || ext.toLowerCase() === '.xls' || ext.toLowerCase() === '.xlsx') { + if (ext === '.csv' || ext === '.xls' || ext === '.xlsx') { this.set('needGeometryFieldName', true); - this.getFieldsFromCsv(); - this.set('warningMessage', this.get('warningMessageSRS')); + this.getFields(); + } + + if (ext === '.gpx' || ext === '.kml') { + this.set('coordinate', 'EPSG:4326'); + } + + if (ext === '.gpx' || ext === '.gml' || ext === '.csv' || ext === '.xls' || ext === '.xlsx') { + this.set('needCRS', true); } - if (ext.toLowerCase() === '.gpx') { + if (ext === '.gpx') { this.set('needGeometryType', true); } diff --git a/addon/components/flexberry-layers-attributes-panel.js b/addon/components/flexberry-layers-attributes-panel.js index 600e11b31..36f69eb93 100644 --- a/addon/components/flexberry-layers-attributes-panel.js +++ b/addon/components/flexberry-layers-attributes-panel.js @@ -948,6 +948,12 @@ export default Ember.Component.extend(SnapDrawMixin, LeafletZoomToFeatureMixin, this.set('loading', false); tabModel._reload(); leafletObject.off('save:failed', saveFailed); + + let _leafletObjectFirst = tabModel.layerModel._leafletObjectFirst; + if (!Ember.isNone(_leafletObjectFirst) && typeof _leafletObjectFirst.setParams === 'function') { + this.trancateGeoWebCache(_leafletObjectFirst, leafletMap); + _leafletObjectFirst.setParams({ fake: Date.now() }, false); + } }; this.set('loading', true); diff --git a/addon/components/flexberry-search-panel.js b/addon/components/flexberry-search-panel.js index 1cf91754e..23df28355 100644 --- a/addon/components/flexberry-search-panel.js +++ b/addon/components/flexberry-search-panel.js @@ -184,6 +184,8 @@ export default Ember.Component.extend({ actions: { querySearch() { + this.sendAction('clearSearch'); + if (this.get('attrVisible')) { if (Ember.isNone(this.get('_selectedLayer'))) { this.set('errorMessage', this.get('i18n').t('components.flexberry-search.error-message-empty-selected-layer')); @@ -275,6 +277,8 @@ export default Ember.Component.extend({ }, attrSearch() { + this.sendAction('clearSearch'); + let attrVisible = !this.get('attrVisible'); if (attrVisible) { this.set('attrVisible', attrVisible); diff --git a/addon/components/flexberry-simpledatetime.js b/addon/components/flexberry-simpledatetime.js index a3f705474..f112e65af 100644 --- a/addon/components/flexberry-simpledatetime.js +++ b/addon/components/flexberry-simpledatetime.js @@ -49,9 +49,21 @@ export default SimpleDatetime.extend({ this.set('eventNamespace', namespace); Ember.$(document).on(`mousedown.${namespace}`, e => { let clicky = Ember.$(e.target); - if (clicky.closest('.flatpickr-calendar').length === 0 && clicky.get(0) !== this.$('.custom-flatpickr').get(0)) { - this.get('_flatpickr').close(); + let flatpickr = this.get('_flatpickr'); + + if (!flatpickr) { + return; + } + + if (clicky.closest('.flatpickr-calendar').length > 0) { + return; } + + if (clicky.get(0) === this.$('.custom-flatpickr').get(0)) { + return; + } + + flatpickr.close(); }); this.$('.custom-flatpickr').on('click', (e) => { this.inputClick(this, e); }); this.$('.button').on('click', (e) => { this.actions.remove(this, e); }); diff --git a/addon/components/geometry-add-modes/draw.js b/addon/components/geometry-add-modes/draw.js index 8214e39a0..b925f81de 100644 --- a/addon/components/geometry-add-modes/draw.js +++ b/addon/components/geometry-add-modes/draw.js @@ -306,12 +306,14 @@ let FlexberryGeometryAddModeDrawComponent = Ember.Component.extend({ } let label = this.get('_dragLayer._label'); - let zoom = Number(this.get('leafletMap').getZoom().toFixed(1)); - let labelZooms = label.filter(l => { return (l.minZoom == null || l.minZoom <= zoom) && (l.maxZoom == null || l.maxZoom >= zoom); }); - if (labelZooms.length > 0) { - let labelZoom = labelZooms[0]; - newCoords = moveCoords(labelZoom.getLatLng()); - labelZoom.setLatLng(newCoords); + if (label) { + let zoom = Number(this.get('leafletMap').getZoom().toFixed(1)); + let labelZooms = label.filter(l => { return (l.minZoom == null || l.minZoom <= zoom) && (l.maxZoom == null || l.maxZoom >= zoom); }); + if (labelZooms.length > 0) { + let labelZoom = labelZooms[0]; + newCoords = moveCoords(labelZoom.getLatLng()); + labelZoom.setLatLng(newCoords); + } } }; diff --git a/addon/components/layer-result-list.js b/addon/components/layer-result-list.js index 09fcff55d..f56c86230 100644 --- a/addon/components/layer-result-list.js +++ b/addon/components/layer-result-list.js @@ -6,6 +6,7 @@ import Ember from 'ember'; import layout from '../templates/components/layer-result-list'; import LeafletZoomToFeatureMixin from '../mixins/leaflet-zoom-to-feature'; import ResultFeatureInitializer from '../mixins/result-feature-initializer'; +import SlotsMixin from 'ember-block-slots'; // Url key used to identify transitions from ember-flexberry-gis on other resources. const isMapLimitKey = 'GISLinked'; @@ -17,7 +18,7 @@ const isMapLimitKey = 'GISLinked'; @uses LeafletZoomToFeatureMixin @extends Ember.Component */ -export default Ember.Component.extend(LeafletZoomToFeatureMixin, ResultFeatureInitializer, { +export default Ember.Component.extend(SlotsMixin, LeafletZoomToFeatureMixin, ResultFeatureInitializer, { /** Service for managing map API. @@ -260,14 +261,6 @@ export default Ember.Component.extend(LeafletZoomToFeatureMixin, ResultFeatureIn this.sendAction('showIntersectionPanel', feature); }, - /** - * Search satellite action - * @param feature - */ - searchSatellites(feature) { - this.sendAction('showSatellitePanel', feature); - }, - /** Action adds feature to favorites. diff --git a/addon/components/layers/odata-vector-layer.js b/addon/components/layers/odata-vector-layer.js index 1486be369..892b77777 100644 --- a/addon/components/layers/odata-vector-layer.js +++ b/addon/components/layers/odata-vector-layer.js @@ -209,7 +209,7 @@ export default BaseVectorLayer.extend({ }); }); - this._createStringLabel([layer], leafletObject.labelsLayers); + this._createStringLabel([layer], leafletObject); } }, @@ -1517,9 +1517,12 @@ export default BaseVectorLayer.extend({ if ((continueLoad && show && checkMapZoom(leafletObject)) || (showLayerObjects && continueLoad)) { let loadedBounds = this.get('loadedBounds'); - let leafletMap = this.get('leafletMap'); let obj = this.get('_adapterStoreModelProjectionGeom'); - let bounds = L.rectangle(leafletMap.getBounds()); + + let boundsMap = this._boundsCrs(leafletObject); + + let bounds = L.rectangle(boundsMap); + if (!Ember.isNone(leafletObject.showLayerObjects)) { leafletObject.showLayerObjects = false; } diff --git a/addon/components/layers/wfs-layer.js b/addon/components/layers/wfs-layer.js index a373195df..ce565e4a8 100644 --- a/addon/components/layers/wfs-layer.js +++ b/addon/components/layers/wfs-layer.js @@ -244,7 +244,7 @@ export default BaseVectorLayer.extend({ }); }); - this._createStringLabel([layer], leafletObject.labelsLayers); + this._createStringLabel([layer], leafletObject); } }, @@ -613,7 +613,7 @@ export default BaseVectorLayer.extend({ break; case 'date': let dateInfo = getDateFormatFromString(e.searchOptions.queryString); - let searchDate = moment.utc(e.searchOptions.queryString, dateInfo.dateFormat + dateInfo.timeFormat, true); + let searchDate = moment(e.searchOptions.queryString, dateInfo.dateFormat + dateInfo.timeFormat, true); if (dateInfo.dateFormat && searchDate.isValid()) { let [startInterval, endInterval] = createTimeInterval(searchDate, dateInfo.dateFormat); @@ -891,7 +891,6 @@ export default BaseVectorLayer.extend({ leafletObject = this.returnLeafletObject(); } - let leafletMap = this.get('leafletMap'); if (!Ember.isNone(leafletObject)) { let show = this.get('visibility') || (!Ember.isNone(leafletObject.showLayerObjects) && leafletObject.showLayerObjects); let continueLoad = !leafletObject.options.showExisting && leafletObject.options.continueLoading; @@ -899,7 +898,8 @@ export default BaseVectorLayer.extend({ let needPromise = false; if (continueLoad && show && checkMapZoom(leafletObject)) { - let bounds = leafletMap.getBounds(); + let bounds = this._boundsCrs(leafletObject); + if (!Ember.isNone(leafletObject.showLayerObjects)) { leafletObject.showLayerObjects = false; } diff --git a/addon/components/legends/-private/vector-legend.js b/addon/components/legends/-private/vector-legend.js index fb0019561..b9c347d20 100644 --- a/addon/components/legends/-private/vector-legend.js +++ b/addon/components/legends/-private/vector-legend.js @@ -22,7 +22,7 @@ export default BaseLegendComponent.extend({ @private @readOnly */ - _styleSettingsRelatedComponentName: Ember.computed('layer.settingsAsObject.styleSettings.type', function() { - return `legends/layers-styles/${this.get('layer.settingsAsObject.styleSettings.type')}`; + _styleSettingsRelatedComponentName: Ember.computed('layer.styleSettingsTypeForLegend', function() { + return `legends/layers-styles/${this.get('layer.styleSettingsTypeForLegend')}`; }) }); diff --git a/addon/components/legends/layers-styles/-private/base.js b/addon/components/legends/layers-styles/-private/base.js index e3d80eadc..70d502b52 100644 --- a/addon/components/legends/layers-styles/-private/base.js +++ b/addon/components/legends/layers-styles/-private/base.js @@ -18,7 +18,8 @@ const flexberryClassNames = { imageWrapper: 'layer-legend-image-wrapper', image: 'layer-legend-image', caption: 'layer-legend-caption', - zoom: 'layer-legend-zoom' + zoom: 'layer-legend-zoom', + marker: 'layer-legend-marker' }; /** diff --git a/addon/components/legends/layers-styles/simple.js b/addon/components/legends/layers-styles/simple.js index ef7ce9f54..fc3aa59e8 100644 --- a/addon/components/legends/layers-styles/simple.js +++ b/addon/components/legends/layers-styles/simple.js @@ -74,12 +74,23 @@ export default BaseLayerStyleLegendComponent.extend({ } if (this.get('_markersCanBeDisplayed')) { - let style = styleRule.styleSettings.style.marker; - let canvas = this.$(`canvas.markers${index}`)[0]; - this._markerLegendRenderer(style, canvas); + let styles = styleRule.styleSettings.style.marker; + if (styles.hasOwnProperty('scale')) { + return; + } + + let markersStylesRenderer = this.get('_markersStylesRenderer'); + let scale = markersStylesRenderer.calcScale(styles); + styles.scale = scale; + Ember.set(styleRule, 'width', scale.size); + Ember.set(styleRule, 'height', scale.size); + + styles.forEach(style => { + markersStylesRenderer.getStyle(scale, style); + }); + } }); - } else { this._withoutStyleRules(); } @@ -93,9 +104,17 @@ export default BaseLayerStyleLegendComponent.extend({ } if (this.get('_markersCanBeDisplayed')) { - let styleSettings = Ember.isNone(this.parentView.layer.legendStyle) ? this.get('styleSettings.style.marker') : this.parentView.layer.legendStyle; - let canvas = this.$('canvas.markers')[0]; - this._markerLegendRenderer(styleSettings, canvas); + let styles = Ember.isNone(this.parentView.layer.legendStyle) ? this.get('styleSettings.style.marker') : this.parentView.layer.legendStyle; + if (styles.hasOwnProperty('scale')) { + return; + } + + let markersStylesRenderer = this.get('_markersStylesRenderer'); + let scale = markersStylesRenderer.calcScale(styles); + styles.scale = scale; + this.set('width', scale.size); + this.set('height', scale.size); + markersStylesRenderer.getStyle(scale, styles); } }, @@ -114,14 +133,5 @@ export default BaseLayerStyleLegendComponent.extend({ canvas: canvas, target: 'legend' }); - }, - - _markerLegendRenderer(styleSettings, canvas) { - let markersStylesRenderer = this.get('_markersStylesRenderer'); - markersStylesRenderer.renderOnCanvas({ - styleSettings: styleSettings, - canvas: canvas, - target: 'legend' - }); - }, + } }); diff --git a/addon/initializers/leaflet-canvas.js b/addon/initializers/leaflet-canvas.js index 65770cb5a..52db0d776 100644 --- a/addon/initializers/leaflet-canvas.js +++ b/addon/initializers/leaflet-canvas.js @@ -40,6 +40,35 @@ export function initialize() { } }, + /** + @method _updateCircle + Override https://github.com/Leaflet/Leaflet/blob/main/src/layer/vector/Canvas.js#L302 + Get ctx and call _fillStroke. + */ + _updateCircle: function (layer) { + + if (!this._drawing || layer._empty()) { return; } + + let p = layer._point; + let ctx = this._ctx; + let r = Math.max(Math.round(layer._radius), 1); + let s = (Math.max(Math.round(layer._radiusY), 1) || r) / r; + + if (s !== 1) { + ctx.save(); + ctx.scale(1, s); + } + + ctx.beginPath(); + ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false); + + if (s !== 1) { + ctx.restore(); + } + + this._fillStroke(ctx, layer.options); + }, + /** @method _fillStroke Override https://github.com/Leaflet/Leaflet/blob/main/src/layer/vector/Canvas.js#L326 diff --git a/addon/initializers/leaflet-path.js b/addon/initializers/leaflet-path.js index 4aa8f5ca7..f97490556 100644 --- a/addon/initializers/leaflet-path.js +++ b/addon/initializers/leaflet-path.js @@ -6,17 +6,43 @@ import Ember from 'ember'; export function initialize() { let setStyle = { setStyle: function (style) { - L.Path.prototype.setStyle.call(this, style); - if (!Ember.isNone(this.layerModel) && Ember.isNone(this.layerModel.legendStyle)) { - this.layerModel.legendStyle = { - type: 'simple', - style: { - path: style + if (style) { + if (this.options.count) { + for (let i = 0; i < this.options.count; i++) { + if (!style.count) { + this.setStyleCustom(this, this.options[i], style); + } else { + L.Path.prototype.setStyle.call(this, style); + } } - }; + } else { + L.Path.prototype.setStyle.call(this, style); + } + + if (!Ember.isNone(this.layerModel) && Ember.isNone(this.layerModel.legendStyle)) { + this.layerModel.legendStyle = { + type: 'simple', + style: { + path: style + } + }; + } } return this; + }, + + setStyleCustom(layer, options, style) { + for (var j in style) { + options[j] = style[j]; + } + + if (layer._renderer) { + layer._renderer._updateStyle(layer); + if (options.stroke && style && style.hasOwnProperty('weight')) { + layer._updateBounds(); + } + } } }; diff --git a/addon/layers-styles/simple.js b/addon/layers-styles/simple.js index 26c0bc9c6..45062eca2 100644 --- a/addon/layers-styles/simple.js +++ b/addon/layers-styles/simple.js @@ -57,10 +57,10 @@ export default BaseLayerStyle.extend({ if (Ember.isNone(path.styleIsSet) || !path.styleIsSet) { let pathStyle = style.path || {}; if (Ember.isArray(pathStyle)) { - pathStyle.forEach(style => { - style = Ember.$.extend(true, {}, style, { + pathStyle.forEach(styleInner => { + styleInner = Ember.$.extend(true, {}, styleInner, { // Fill must be disabled for non polygon layers, because filled polylines and other lines-like geometries looks ugly in leaflet. - fill: style.fill === true && path instanceof L.Polygon + fill: styleInner.fill === true && path instanceof L.Polygon }); }); pathStyle.count = pathStyle.length; diff --git a/addon/layers/-private/base.js b/addon/layers/-private/base.js index c91dfc0f4..23b5385be 100644 --- a/addon/layers/-private/base.js +++ b/addon/layers/-private/base.js @@ -142,6 +142,36 @@ export default Ember.Object.extend({ return settings; }, + /** + Type of legend. + @property getLegendType + @type String + @readOnly + */ + getLegendType(type, settingsAsObject) { + return type; + }, + + /** + Settings of legend. + @property getLegendSettings + @type Object + @readOnly + */ + getLegendSettings(settingsAsObject) { + return settingsAsObject.legendSettings; + }, + + /** + Type of legend from style settings. + @property getStyleSettingsTypeForLegend + @type String + @readOnly + */ + getStyleSettingsTypeForLegend(settingsAsObject) { + return settingsAsObject.styleSettings.type; + }, + /** Creates new settings object (with settings related to layer-type) from the specified CSW record. diff --git a/addon/layers/wms-wfs.js b/addon/layers/wms-wfs.js index 291b311de..6719cdcbe 100644 --- a/addon/layers/wms-wfs.js +++ b/addon/layers/wms-wfs.js @@ -56,6 +56,48 @@ export default WmsLayer.extend({ return settings; }, + /** + Type of legend. + @property getLegendType + @type String + @readOnly + */ + getLegendType(type, settingsAsObject) { + if (settingsAsObject.remoteStyles === false) { + return 'wfs'; + } + + return type; + }, + + /** + Settings of legend. + @property getLegendSettings + @type Object + @readOnly + */ + getLegendSettings(settingsAsObject) { + if (settingsAsObject.remoteStyles === false) { + return settingsAsObject.wfs.legendSettings; + } + + return settingsAsObject.legendSettings; + }, + + /** + Type of legend from style settings. + @property getStyleSettingsTypeForLegend + @type String + @readOnly + */ + getStyleSettingsTypeForLegend(settingsAsObject) { + if (settingsAsObject.remoteStyles === false) { + return settingsAsObject.wfs.styleSettings.type; + } + + return settingsAsObject.styleSettings.type; + }, + /** Creates new search settings object (with search settings related to layer-type). diff --git a/addon/markers-styles/default.js b/addon/markers-styles/default.js index 8e58ff509..dc7b7a833 100644 --- a/addon/markers-styles/default.js +++ b/addon/markers-styles/default.js @@ -54,11 +54,11 @@ export default BaseMarkerStyle.extend({ @param {Object} options.style Hash containing style settings. @param {Object} [options.target = 'preview'] Render target ('preview' or 'legend'). */ - renderOnCanvas({ canvas, style, target }) { + renderOnCanvas({ canvas, style, target, scale }) { // Default 'image' markers-style's settings are settings for leaflet default image icon (L.Icon.Default), // so we can reuse 'image' markers-style here. let markersStylesRenderer = this.get('_markersStylesRenderer'); let defaultMarkerStyleSettings = markersStylesRenderer.getDefaultStyleSettings('image'); - markersStylesRenderer.renderOnCanvas({ canvas, styleSettings: defaultMarkerStyleSettings, target }); + markersStylesRenderer.renderOnCanvas({ canvas, styleSettings: defaultMarkerStyleSettings, target, scale }); } }); diff --git a/addon/markers-styles/image.js b/addon/markers-styles/image.js index 0484cd383..ee2c1ad5c 100644 --- a/addon/markers-styles/image.js +++ b/addon/markers-styles/image.js @@ -36,7 +36,9 @@ export default BaseMarkerStyle.extend({ shadowSize: [41, 41], // Shadow icon anchor relative to it's size. - shadowAnchor: [12, 41] + shadowAnchor: [12, 41], + + iconType: 'default' }; }, @@ -52,82 +54,5 @@ export default BaseMarkerStyle.extend({ if (Ember.isNone(marker.styleIsSet) || !marker.styleIsSet) { marker.setIcon(new L.Icon(style)); } - }, - - /** - Renderes marker-style preview on the specified canvas element. - - @method renderOnCanvas - @param {Object} options Method options. - @param {Canvas} options.canvas Canvas element on which marker-style preview must be rendered. - @param {Object} options.style Hash containing style settings. - @param {Object} [options.target = 'preview'] Render target ('preview' or 'legend'). - */ - renderOnCanvas({ canvas, style, target }) { - let width = canvas.width; - let height = canvas.height; - let ctx = canvas.getContext('2d'); - - // Clear canvas. - ctx.clearRect(0, 0, width, height); - - var iconImage = new Image(); - iconImage.onload = function() { - // Draw loaded image. - let iconWidth = style.iconSize[0] || iconImage.width; - let iconHeight = style.iconSize[1] || iconImage.height; - - let scale = iconWidth > width || iconHeight > height ? - Math.min(width / iconWidth, height / iconHeight) : - 1; - let xOffset = (width - iconWidth * scale) / 2; - let yOffset = (height - iconHeight * scale) / 2; - - let drawIconImage = function() { - ctx.drawImage(iconImage, xOffset, yOffset, iconWidth * scale, iconHeight * scale); - }; - - if (Ember.isBlank(style.shadowUrl)) { - drawIconImage(); - } else { - let shadowImage = new Image(); - shadowImage.onload = function() { - // Draw shadow icon. - let shadowWidth = style.shadowSize[0] || shadowImage.width; - let sadowHeight = style.shadowSize[1] || shadowImage.height; - - let xShadowOffset = style.iconAnchor[0] - style.shadowAnchor[0]; - let yShadowOffset = style.iconAnchor[1] - style.shadowAnchor[1]; - ctx.drawImage(shadowImage, xOffset + xShadowOffset, yOffset + yShadowOffset, shadowWidth * scale, sadowHeight * scale); - - // Draw marker icon. - drawIconImage(); - }; - - shadowImage.onerror = function() { - // Shadow is optional, so draw marker icon anyway. - drawIconImage(); - }; - - // Set shadow image src to start loading. - shadowImage.src = style.shadowUrl; - } - }; - - iconImage.onerror = function() { - // Draw red cross instead of image. - ctx.moveTo(0, 0); - ctx.lineTo(width, height); - - ctx.moveTo(width, 0); - ctx.lineTo(0, height); - - ctx.lineWidth = 4; - ctx.strokeStyle = '#ff0000'; - ctx.stroke(); - }; - - // Set image src to start loading. - iconImage.src = style.iconUrl; } }); diff --git a/addon/mixins/edit-feature.js b/addon/mixins/edit-feature.js index 75836b72c..ac54c8343 100644 --- a/addon/mixins/edit-feature.js +++ b/addon/mixins/edit-feature.js @@ -1,5 +1,6 @@ import Ember from 'ember'; +import { getLeafletCrs } from '../utils/leaflet-crs'; export default Ember.Mixin.create({ @@ -54,5 +55,80 @@ export default Ember.Mixin.create({ return L.geoJson(layer.toGeoJSON(), { pane: 'zoomto' }).setStyle(this.get('zoomFeatureStyle')); + }, + + /** + Sends request to trancate GeoWebCache for layer by boundingBox. + + @method trancateGeoWebCache + @param {Object} leafletObject laeflet layer. + @param {Object} leafletMap laeflet map. + */ + trancateGeoWebCache(leafletObject, leafletMap) { + let layers = leafletObject.wmsParams.layers.split(); + let workspace; + let layer; + let geoWebCache; + if (layers.length === 2) { + workspace = layers[0]; + layer = layers[1]; + } else { + let urlSplit = leafletObject._url.split('/'); + let indexGeoserver = urlSplit.indexOf('geoserver'); + if (indexGeoserver > -1 && urlSplit.length === indexGeoserver + 3) { + workspace = urlSplit.at(indexGeoserver + 1); + } else { + console.error('Can\'t get workspace in geoserver'); + return; + } + + layer = layers[0]; + } + + if (!Ember.isBlank(leafletObject._url.match(new RegExp('(https?|ftp)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?')))) { + let indexGeoserver = leafletObject._url.indexOf('geoserver'); + if (indexGeoserver === -1) { + console.error('Can\'t get url geoserver'); + return; + } + + geoWebCache = leafletObject._url.slice(0, indexGeoserver + 10) + '/gwc/rest/seed/'; + } + + if (!Ember.isNone(geoWebCache)) { + let url = geoWebCache + workspace + ':' + layer; + let gridSetId = leafletObject.wmsParams.crs + '_' + leafletObject.wmsParams.width; + let zoom = Math.trunc(leafletMap.getZoom()); + let zoomStart = zoom - 1 > 0 ? zoom - 1 : zoom; + let zoomStop = zoom + 1 < 20 ? zoom + 1 : zoom; + let styles = leafletObject.wmsParams.styles; + let parameterStyles = ''; + if (!Ember.isNone(styles)) { + parameterStyles = `parameter_STYLES=${workspace}:${styles}&`; + } + + let crsName = leafletObject.wmsParams.crs; + let crs; + if (!Ember.isNone(crsName)) { + crs = getLeafletCrs('{ "code": "' + crsName.toUpperCase() + '", "definition": "" }', this); + } + + let bounds = leafletMap.getBounds(); + let minXY = L.marker(bounds._southWest).toProjectedGeoJSON(crs); + let maxXY = L.marker(bounds._northEast).toProjectedGeoJSON(crs); + + Ember.$.ajax({ + method: 'POST', + url: url, + async: true, + data: `threadCount=01&type=truncate&gridSetId=${gridSetId}&tileFormat=image%2Fpng&zoomStart=${zoomStart}&zoomStop=${zoomStop}&` + + `${parameterStyles}minX=${minXY.geometry.coordinates[0]}&minY=${minXY.geometry.coordinates[1]}` + + `&maxX=${maxXY.geometry.coordinates[0]}&maxY=${maxXY.geometry.coordinates[1]}`, + contentType: 'text/html', + error: function (data) { + console.error(data); + } + }); + } } }); diff --git a/addon/mixins/flexberry-check-file.js b/addon/mixins/flexberry-check-file.js index 22b260831..ca59edc3c 100644 --- a/addon/mixins/flexberry-check-file.js +++ b/addon/mixins/flexberry-check-file.js @@ -49,6 +49,10 @@ export default Ember.Mixin.create({ let layer = null; try { + let features = response.features.filter((feature) => { + return !Ember.isNone(feature.geometry) && feature.geometry.coordinates.flat(5).length > 0; + }); + response.features = features; layer = this._createLayer(response, crs); } catch (ex) { @@ -109,7 +113,7 @@ export default Ember.Mixin.create({ let ajax = this.get('fileLoadAjax'); if (ajax) { if (ajax.readyState === 4 && ajax.status === 200) { - resolve(this.get('fileLoadAjax').responseJSON); + resolve(JSON.parse(this.get('fileLoadAjax').responseText || '{}')); return; } @@ -126,7 +130,7 @@ export default Ember.Mixin.create({ let url = `${config.APP.backendUrls.geomFileValidationUrl}?FileName=${file.name}`; let data = new FormData(); data.append(file.name, file); - data.append('crs', this.get('coordinate')); + data.append('fileCrs', this.get('coordinate')); if (this.get('needGeometryType')) { data.append('typeGeometryLayer', this.get('_geometryType')); @@ -149,11 +153,12 @@ export default Ember.Mixin.create({ processData: false }).done((response) => { this._showHideLoader(false); - if (response && response.features) { - this.set('coordinate', response.definedCrs); - this.set('geometryType', this.getGeometryType(response.features[0].geometry.type)); + let jsonResponse = JSON.parse(response || '{}'); + if (jsonResponse.features) { + this.set('coordinate', jsonResponse.definedCrs); + this.set('geometryType', this.getGeometryType(jsonResponse.features[0].geometry.type)); - resolve(response); + resolve(jsonResponse); } else { reject({ message: this.get('emptyErrorMessage') diff --git a/addon/mixins/flexberry-map-model-api.js b/addon/mixins/flexberry-map-model-api.js index dccf13634..fe7d684bb 100644 --- a/addon/mixins/flexberry-map-model-api.js +++ b/addon/mixins/flexberry-map-model-api.js @@ -1214,7 +1214,7 @@ export default Ember.Mixin.create(SnapDraw, actionsHandler, { return new Ember.RSVP.Promise((resolve, reject) => { Ember.$.ajax({ - url: `${config.APP.backendUrl}/controls/FileUploaderHandler.ashx?FileName=${file.name}`, + url: `${config.APP.backendUrls.fileUploadUrl}?FileName=${file.name}`, type: 'POST', data: data, cache: false, diff --git a/addon/mixins/flexberry-maplayer-actions-handler.js b/addon/mixins/flexberry-maplayer-actions-handler.js index 9064a1ee6..55dc70edc 100644 --- a/addon/mixins/flexberry-maplayer-actions-handler.js +++ b/addon/mixins/flexberry-maplayer-actions-handler.js @@ -404,7 +404,7 @@ export default Ember.Mixin.create({ let rootArray = this.get(rootPath); rootArray.pushObject(childLayer); - setIndexes(rootArray, this.get('model.hierarchy')); + setIndexes(rootArray, this.get('model.otherLayers')); }, /** @@ -539,7 +539,7 @@ export default Ember.Mixin.create({ let rootArray = this.get(rootPath); - setIndexes(rootArray, this.get('model.hierarchy')); + setIndexes(rootArray, this.get('model.otherLayers')); } }, diff --git a/addon/mixins/layer-label.js b/addon/mixins/layer-label.js index 799ef04fc..aceff1526 100644 --- a/addon/mixins/layer-label.js +++ b/addon/mixins/layer-label.js @@ -206,7 +206,7 @@ export default Ember.Mixin.create({ @param {Object} layer layer @return {String} string with replaced property */ - _applyProperty(str, layer) { + _applyProperty(str, layer, leafletObject) { let hasReplace = false; let propName; @@ -230,7 +230,7 @@ export default Ember.Mixin.create({ } if (property && layer.feature.properties && layer.feature.properties.hasOwnProperty(property)) { - str = this._labelValue(layer, property, prop, str); + str = this._labelValue(layer, property, prop, str, leafletObject); } } } @@ -242,8 +242,11 @@ export default Ember.Mixin.create({ } }, - _labelValue(layer, property, prop, str) { - let leafletObject = this.returnLeafletObject(); + _labelValue(layer, property, prop, str, leafletObject) { + if (Ember.isNone(leafletObject)) { + leafletObject = this.returnLeafletObject(); + } + let readFormat = Ember.get(leafletObject, 'readFormat.featureType.fieldTypes'); let label = layer.feature.properties[property]; let dateTimeFormat = this.displaySettings.dateTimeFormat; @@ -329,9 +332,8 @@ export default Ember.Mixin.create({ @method _showLabelsMovingMap */ _showLabelsMovingMap() { - let labelsLayers = this.get('labelsLayers'); let leafletObject = this.returnLeafletObject(); - this._createStringLabel(leafletObject.getLayers(), labelsLayers); + this._createStringLabel(leafletObject.getLayers(), leafletObject); }, /** @@ -340,7 +342,7 @@ export default Ember.Mixin.create({ @method _createStringLabel @param {Array} layers new layers for add labels */ - _createStringLabel(layers) { + _createStringLabel(layers, leafletObject) { if (layers) { let labelsLayerZoom = this._getLabelsLayersZoom(); if (labelsLayerZoom) { @@ -358,7 +360,7 @@ export default Ember.Mixin.create({ `text-align: ${Ember.get(optionsLabel, 'captionFontAlign')};${halo}`); this._checkLabelInView(layers, labelsLayerZoom).forEach(layer => { - let label = layer.labelValue || this._applyFunction(this._applyProperty(labelSettingsString, layer)); + let label = layer.labelValue || this._applyFunction(this._applyProperty(labelSettingsString, layer, leafletObject)); this._createLabel(label, layer, style, labelsLayerZoom); }); } @@ -426,21 +428,28 @@ export default Ember.Mixin.create({ let className = 'label'; className += ' point ' + positionPoint.cssClass; let html = '