let ol = require('openlayers');
let axios = require('axios');
let jquery = require('jquery');
let AbstractDataSource = require('./abstractDataSource');
let TransactionItem = require('./../editing/transactionItem');
let TransactionStack = require('./../editing/transactionStack');
let scalarTypes = require('./../constants/scalarType');
/**
* Класс EsriJsonVectorSource предназначен для создания векторного источника данных для ESRI REST API сервисов
* @extends AbstractDataSource
*/
class EsriJsonVectorSource extends AbstractDataSource {
/**
* Создает экземпляр класса EsriJsonVectorSource
* @param params
*/
constructor(params) {
super(params);
this.source = this.create(params);
this.type = "esriJsonVectorSource";
this.loadSourceProperties().then((data) => {
this.dataSourceParams = data;
});
}
/**
* Выполняет загрузку и инициализацию свойств источника
* @return {Promise.<{}>}
*/
async loadSourceProperties() {
let self = this;
let url = self.params.url + "?f=pjson";
let sourceProperties = (await axios.get(url)).data;
const esriGeometryTypes = {
"esriGeometryPoint": "Point",
"esriGeometryPolyline": "MultiLineString",
"esriGeometryPolygon": "MultiPolygon"
};
self.geometryType = esriGeometryTypes[sourceProperties.geometryType];
return sourceProperties
}
/**
* Метод, возвращающий тип геометрии источника векторных данных
* @return {string} - geometryType - Point, LineString, Polygon
*/
getGeometryType() {
return this.geometryType;
}
/**
* Метод возвращает информацию по полям источника данных - для получения информации в виде массива или объекта используйте getArray() или getObject(), соответственно
* @return {{getArray: (function()), getObject: (function())}}
*/
getFields() {
let self = this;
let dataSourceParams = self.dataSourceParams;
let fieldLikeArray = [];
let fields = dataSourceParams.fields;
if (fields.length > 0) {
fieldLikeArray = fields;
}
fieldLikeArray = fieldLikeArray.map((item) => {
let result = {
localType: item.type,
name: item.name,
alias: this.getFieldAlias(item),
type: scalarTypes.convertToJsType("esri", item.type),
isNullable: item.nullable,
isRequired: false,
};
return result;
});
let fieldsLikeObject = {};
for (let i = 0; i < fieldLikeArray.length; i++) {
fieldsLikeObject[fieldLikeArray[i].name] = fieldLikeArray[i];
}
let fieldsObject = {
getArray: () => {
return fieldLikeArray;
},
getObject: () => {
return fieldsLikeObject;
}
};
}
/**
* Возвращает ссылку на экземпляр источника
* @return {*}
*/
getSource() {
return this.source;
}
getDescriptor() {
return this;
}
/**
* Обновление features
*/
updateFeatures(params) {
let self = this;
let featureId = params.featureId;
let feature = params.feature;
self.removeFeature(feature);
self.loadFeatureFromService(featureId);
}
/**
* Получение feature из сервиса
* @param featureId {string} - featureId
*/
async loadFeatureFromService(featureId) {
let self = this;
let url = self.params.url;
let source = self.getSource();
let nameSpace = self.params.className.split(":")[0];
let className = self.params.className;
let formatJson = new ol.format.GeoJSON();
let response = await axios.get(url + nameSpace + "/ows", {
params: {
service: 'WFS',
version: '1.0.0',
request: 'GetFeature',
typeName: className,
outputFormat: "json",
featureId: featureId
}
});
source.addFeatures(formatJson.readFeatures(response.data));
return response;
}
/**
* Получить список объектов источника
* @param params
* @return {*|Array.<ol.Feature|ol.render.Feature>|ol.Collection.<ol.Feature>|Array.<ol.Feature>}
*/
getFeatures(params) {
let self = this;
let source = self.source;
return source.getFeatures();
}
/**
* Добавить объекты в источник
* @param data
*/
addFeatures(data) {
let self = this;
let source = self.source;
source.addFeatures(data);
}
/**
* Удаление feature из источника
* @param feature
*/
removeFeature(feature) {
let self = this;
let source = self.source;
source.removeFeature(feature);
}
/**
* Удаление feature из источника через указания свойства и значения
* @param {object} params - параметры поиска
* @param params.key {string} - имя свойства
* @param params.value {string} - искомое значение
*/
removeFeatureByProperty(params) {
let self = this;
let key = params.key;
let value = params.value;
if (key && value) {
let features = self.getFeatures();
let feature = features.find((item) => {
let testValue = feature.get(key);
if (testValue === value) return true;
});
if (feature) {
self.removeFeature(feature);
}
}
}
/**
* Применяет новый источник данных
* @param source
* @return {EsriJsonVectorSource} - источник данных
*/
setSource(source) {
this.source = source;
return this;
}
/**
* Инициализирует (и позволяет выполнить реинициализацию) источника данных
* @param params
* @return {ol.source.Vector}
*/
create(params) {
let formatJson = new ol.format.EsriJSON();
let tiles = params.tiles || 2;
let url = params.url;
let source = new ol.source.Vector({
loader: function (extent) {
for (let i = 0; i < tiles; i++) {
for (let j = 0; j < tiles; j++) {
let dx = Math.abs(extent[2] - extent[0]) / 2;
let dy = Math.abs(extent[3] - extent[1]) / 2;
let minx = extent[0] + dx * i;
let miny = extent[1] + dy * j;
let maxx = extent[0] + dx * (i + 1);
let maxy = extent[1] + dy * (j + 1);
axios.get(url + "/query", {
params: {
where: "1=1",
geometryType: "esriGeometryEnvelope",
spatialRel: "esriSpatialRelIntersects",
outFields: params.outFields || '*',
srsname: 'EPSG:3857',
geometry: {xmin: minx, ymin: miny, xmax: maxx, ymax: maxy},
returnGeometry: params.returnGeometry || true,
f: "pjson"
}
}).then((response) => {
source.addFeatures(formatJson.readFeatures(response.data));
});
}
}
},
//создает стратегию для загрузки карты
strategy: ol.loadingstrategy.bbox || params.strategy,
projection: 'EPSG:3857' || params.projection
});
return source;
}
/**
* Создание объекта транзаксии
* @param params
* @return {TransactionItem} - транзакция
*/
createTransaction(params) {
let self = this;
let serverUrl = self.params.url;
let feature = params.feature;
let transactionType = params.transactionType;
let esriJsonFormat = new ol.format.EsriJSON();
let url;
let payload = "[" + esriJsonFormat.writeFeature(feature) + "]";
payload = JSON.parse(payload);
switch (transactionType) {
case 'insert':
url = serverUrl + '/addFeatures';
break;
case 'update':
url = serverUrl + '/updateFeatures';
break;
case 'delete':
url = serverUrl + '/deleteFeatures';
break;
}
let action = {
url: url,
method: 'POST',
typ: 'POST',
data: {
features: JSON.stringify(payload),
f: "pjson",
rollbackOnFailure: true
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
return new TransactionItem({
action: action,
executor: jquery.post,
className: self.params.className,
layerId: self.params.id,
sourceObject: self.getDescriptor(),
feature: feature,
transactionType: params.transactionType
})
}
/**
* Непосредственное выполнение транзакции
* @param params
* @return {Promise.<*>}
*/
async transact(params) {
let self = this;
let transaction = self.createTransaction(params);
let executor = transaction.executor;
let action = transaction.action;
return executor(action);
}
/**
* Перемещение транзакции в стек операций редактирования
* @param params
* @return {{transaction: TransactionItem}}
*/
toStack(params) {
let self = this;
let transaction = self.createTransaction(params);
TransactionStack.push(transaction);
return {
transaction: transaction
}
}
fromStack(params) {
}
}
module.exports = EsriJsonVectorSource;