Example of using an ArcGIS REST Feature Service in an editing application.
This example loads features from ArcGIS REST Feature Service and allows to add new features or update existing features.
import 'ol/ol.css';
import EsriJSON from 'ol/format/EsriJSON';
import Map from 'ol/Map';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import XYZ from 'ol/source/XYZ';
import {
Draw,
Modify,
Select,
defaults as defaultInteractions,
} from 'ol/interaction';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {createXYZ} from 'ol/tilegrid';
import {fromLonLat} from 'ol/proj';
import {tile as tileStrategy} from 'ol/loadingstrategy';
const serviceUrl =
'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire/FeatureServer/';
const layer = '2';
const esrijsonFormat = new EsriJSON();
const vectorSource = new VectorSource({
loader: function (extent, resolution, projection) {
const url =
serviceUrl +
layer +
'/query/?f=json&' +
'returnGeometry=true&spatialRel=esriSpatialRelIntersects&geometry=' +
encodeURIComponent(
'{"xmin":' +
extent[0] +
',"ymin":' +
extent[1] +
',"xmax":' +
extent[2] +
',"ymax":' +
extent[3] +
',"spatialReference":{"wkid":102100}}'
) +
'&geometryType=esriGeometryEnvelope&inSR=102100&outFields=*' +
'&outSR=102100';
$.ajax({
url: url,
dataType: 'jsonp',
success: function (response) {
if (response.error) {
alert(
response.error.message + '\n' + response.error.details.join('\n')
);
} else {
// dataProjection will be read from document
const features = esrijsonFormat.readFeatures(response, {
featureProjection: projection,
});
if (features.length > 0) {
vectorSource.addFeatures(features);
}
}
},
});
},
strategy: tileStrategy(
createXYZ({
tileSize: 512,
})
),
});
const vector = new VectorLayer({
source: vectorSource,
});
const raster = new TileLayer({
source: new XYZ({
attributions:
'Tiles © <a href="https://services.arcgisonline.com/ArcGIS/' +
'rest/services/World_Topo_Map/MapServer">ArcGIS</a>',
url:
'https://server.arcgisonline.com/ArcGIS/rest/services/' +
'World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
}),
});
const draw = new Draw({
source: vectorSource,
type: 'Polygon',
});
const select = new Select();
select.setActive(false);
const selected = select.getFeatures();
const modify = new Modify({
features: selected,
});
modify.setActive(false);
const map = new Map({
interactions: defaultInteractions().extend([draw, select, modify]),
layers: [raster, vector],
target: document.getElementById('map'),
view: new View({
center: fromLonLat([-110.875, 37.345]),
zoom: 5,
}),
});
const typeSelect = document.getElementById('type');
/**
* Let user change the interaction type.
*/
typeSelect.onchange = function () {
draw.setActive(typeSelect.value === 'DRAW');
select.setActive(typeSelect.value === 'MODIFY');
modify.setActive(typeSelect.value === 'MODIFY');
};
const dirty = {};
selected.on('add', function (evt) {
const feature = evt.element;
feature.on('change', function (evt) {
dirty[evt.target.get('objectid')] = true;
});
});
selected.on('remove', function (evt) {
const feature = evt.element;
const fid = feature.get('objectid');
if (dirty[fid] === true) {
const payload =
'[' +
esrijsonFormat.writeFeature(feature, {
featureProjection: map.getView().getProjection(),
}) +
']';
const url = serviceUrl + layer + '/updateFeatures';
$.post(url, {f: 'json', features: payload}).done(function (data) {
const result = typeof data === 'string' ? JSON.parse(data) : data;
if (result.updateResults && result.updateResults.length > 0) {
if (result.updateResults[0].success !== true) {
const error = result.updateResults[0].error;
alert(error.description + ' (' + error.code + ')');
} else {
delete dirty[fid];
}
}
});
}
});
draw.on('drawend', function (evt) {
const feature = evt.feature;
const payload =
'[' +
esrijsonFormat.writeFeature(feature, {
featureProjection: map.getView().getProjection(),
}) +
']';
const url = serviceUrl + layer + '/addFeatures';
$.post(url, {f: 'json', features: payload}).done(function (data) {
const result = typeof data === 'string' ? JSON.parse(data) : data;
if (result.addResults && result.addResults.length > 0) {
if (result.addResults[0].success === true) {
feature.set('objectid', result.addResults[0]['objectId']);
} else {
const error = result.addResults[0].error;
alert(error.description + ' (' + error.code + ')');
}
}
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Editable ArcGIS REST Feature Service</title>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep@1.0.6/dist/elm-pep.js"></script>
<!-- The lines below are only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,TextDecoder"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.18.3/minified.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<style>
.map {
width: 100%;
height:400px;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<form class="form-inline">
<label for="type">Draw or modify </label>
<select id="type">
<option value="DRAW">Draw</option>
<option value="MODIFY">Modify</option>
</select>
</form>
<script src="main.js"></script>
</body>
</html>
{
"name": "vector-esri-edit",
"dependencies": {
"ol": "6.13.1-dev"
},
"devDependencies": {
"parcel": "^2.0.0"
},
"scripts": {
"start": "parcel index.html",
"build": "parcel build --public-url . index.html"
}
}