Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch everything #1229

Merged
merged 10 commits into from
Oct 5, 2020
285 changes: 284 additions & 1 deletion spec/Layers/FeatureLayer/FeatureManagerSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,46 @@ describe('L.esri.FeatureManager', function () {
}
};

// geojson:
var feature7 = {
'type': 'Feature',
'geometry':
{
'type': 'Polygon',
'coordinates':
[
[
[-90.3038149502124, 38.6539545785218],
[-90.3038498654697, 38.6539303067945],
[-90.3038737094094, 38.6539138632284],
[-90.3039181787535, 38.6538794680055],
[-90.3042877084603, 38.6542092694323],
[-90.3042196068492, 38.6542595646522],
[-90.3041648638806, 38.6542969769789],
[-90.3038149502124, 38.6539545785218]
]
]
},
'properties': null
};

var feature8 = {
'type': 'Feature',
'geometry':
{
'type': 'Polygon',
'coordinates':
[
[
[-90.3038149502124, 38.6539545785218],
[-90.3038498654697, 38.6539303067945],
[-90.3038737094094, 38.6539138632284]
]
]
},
'properties': null
};

it('should be able to add itself to a map', function () {
layer.addTo(map);
expect(map.hasLayer(layer)).to.equal(true);
Expand Down Expand Up @@ -253,7 +293,6 @@ describe('L.esri.FeatureManager', function () {
layer.addTo(map);

server.respond();

expect(layer.createLayers).to.have.been.calledWith([
{
type: 'Feature',
Expand Down Expand Up @@ -1216,5 +1255,249 @@ describe('L.esri.FeatureManager', function () {
expect(layer._activeRequests).to.equal(0);
expect(triggered).to.be.true;
});

it('should fetch as geojson if "isModern" is true', function () {
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultOffset=0&resultType=tile&f=geojson',
JSON.stringify({
'type': 'FeatureCollection',
'features': [feature7]})
);

var layer = new MockLayer({
url:
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/',
fetchAllFeatures: true,
isModern: true
});

layer.addTo(map);
server.respond();
expect(layer.createLayers).to.have.been.calledWith([feature7]);
});

it('should fetch another request if limit exceeded', function () {
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultOffset=0&resultType=tile&f=json',
JSON.stringify({
fields: fields,
features: [feature6],
objectIdFieldName: 'OBJECTID',
exceededTransferLimit: true
})
);

var layer = new MockLayer({
url:
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/',
fetchAllFeatures: true
});

layer.addTo(map);
server.respond();
expect(layer.createLayers).to.have.been.calledWith([
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [
[
[-109.02, 36.98],
[-102.06, 37.01],
[-102.06, 40.97],
[-109.02, 40.97],
[-109.02, 36.98]
]
]
},
properties: {
OBJECTID: 6,
Name: 'Site 6',
Type: 'Active',
StartTime: new Date('January 14 2014 GMT-0800').valueOf(),
EndTime: new Date('January 15 2014 GMT-0800').valueOf()
},
id: 6
}
]);

// second call due to fetchAllFeatures
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultOffset=1&resultType=tile&f=json',
JSON.stringify({
fields: fields,
features: [feature5],
objectIdFieldName: 'OBJECTID'
})
);
server.respond();
expect(layer.createLayers).to.have.been.calledWith([
{
geometry: {
type: 'Point',
coordinates: [-122.629394, 45.537134]
},
id: 5,
properties: {
OBJECTID: 5,
Name: 'Site 5',
Type: 'Active',
StartTime: new Date('January 14 2014 GMT-0800').valueOf(),
EndTime: new Date('January 15 2014 GMT-0800').valueOf()
},
type: 'Feature'
}
]);
});

it('should fetch another request if limit exceeded - geojson exceededTransferLimit', function () {
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultOffset=0&resultType=tile&f=geojson',
JSON.stringify({
'type': 'FeatureCollection',
'features': [feature7],
'exceededTransferLimit': true
})
);

var layer = new MockLayer({
url:
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/',
fetchAllFeatures: true,
isModern: true
});

layer.addTo(map);
server.respond();
expect(layer.createLayers).to.have.been.calledWith([feature7]);

// second call due to fetchAllFeatures
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultOffset=1&resultType=tile&f=geojson',
JSON.stringify({
'type': 'FeatureCollection',
'features': [feature8]
})
);
server.respond();
expect(layer.createLayers).to.have.been.calledWith([feature8]);
});

it('should fetch another request if limit exceeded - geojson properties.exceededTransferLimit', function () {
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultOffset=0&resultType=tile&f=geojson',
JSON.stringify({
'type': 'FeatureCollection',
'features': [feature7],
'properties': {
'exceededTransferLimit': true
}
})
);

var layer = new MockLayer({
url:
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/',
fetchAllFeatures: true,
isModern: true
});

layer.addTo(map);
server.respond();
expect(layer.createLayers).to.have.been.calledWith([feature7]);

// second call due to fetchAllFeatures
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultOffset=1&resultType=tile&f=geojson',
JSON.stringify({
'type': 'FeatureCollection',
'features': [feature8]
})
);
server.respond();
expect(layer.createLayers).to.have.been.calledWith([feature8]);
});

it('should not fetch another request even if limit exceeded when no "fetchAllFeatures"', function () {
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultType=tile&f=json',
JSON.stringify({
fields: fields,
features: [feature6],
objectIdFieldName: 'OBJECTID',
exceededTransferLimit: true
})
);

var layer = new MockLayer({
url:
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/'
});

layer.addTo(map);
server.respond();
expect(layer.createLayers).to.have.been.calledWith([
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [
[
[-109.02, 36.98],
[-102.06, 37.01],
[-102.06, 40.97],
[-109.02, 40.97],
[-109.02, 36.98]
]
]
},
properties: {
OBJECTID: 6,
Name: 'Site 6',
Type: 'Active',
StartTime: new Date('January 14 2014 GMT-0800').valueOf(),
EndTime: new Date('January 15 2014 GMT-0800').valueOf()
},
id: 6
}
]);

// unexpected second call
server.respondWith(
'GET',
'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/query?returnGeometry=true&where=1%3D1&outSR=4326&outFields=*&inSr=4326&geometry=%7B%22xmin%22%3A-122.6513671875%2C%22ymin%22%3A45.49094569262732%2C%22xmax%22%3A-122.607421875%2C%22ymax%22%3A45.521743896993634%2C%22spatialReference%22%3A%7B%22wkid%22%3A4326%7D%7D&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&geometryPrecision=6&resultOffset=1&resultType=tile&f=json',
JSON.stringify({
fields: fields,
features: [feature5],
objectIdFieldName: 'OBJECTID'
})
);
server.respond();
expect(layer.createLayers).not.to.have.been.calledWith([
{
geometry: {
type: 'Point',
coordinates: [-122.629394, 45.537134]
},
id: 5,
properties: {
OBJECTID: 5,
Name: 'Site 5',
Type: 'Active',
StartTime: new Date('January 14 2014 GMT-0800').valueOf(),
EndTime: new Date('January 15 2014 GMT-0800').valueOf()
},
type: 'Feature'
}
]);
});
});
/* eslint-enable handle-callback-err */
23 changes: 17 additions & 6 deletions src/Layers/FeatureLayer/FeatureManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export var FeatureManager = FeatureGrid.extend({
timeField: false,
timeFilterMode: 'server',
simplifyFactor: 0,
precision: 6
precision: 6,
fetchAllFeatures: false
},

/**
Expand Down Expand Up @@ -75,7 +76,7 @@ export var FeatureManager = FeatureGrid.extend({

// Check if someone has requested that we don't use geoJSON, even if it's available
var forceJsonFormat = false;
if (this.service.options.isModern === false) {
if (this.service.options.isModern === false || this.options.fetchAllFeatures) {
forceJsonFormat = true;
}

Expand Down Expand Up @@ -130,9 +131,12 @@ export var FeatureManager = FeatureGrid.extend({
}
},

_requestFeatures: function (bounds, coords, callback) {
_requestFeatures: function (bounds, coords, callback, offset) {
this._activeRequests++;

// default param
offset = offset || 0;

var originalWhere = this.options.where;

// our first active request fires loading
Expand All @@ -146,7 +150,7 @@ export var FeatureManager = FeatureGrid.extend({
);
}

return this._buildQuery(bounds).run(function (
return this._buildQuery(bounds, offset).run(function (
error,
featureCollection,
response
Expand Down Expand Up @@ -183,8 +187,11 @@ export var FeatureManager = FeatureGrid.extend({
if (callback) {
callback.call(this, error, featureCollection);
}
if (response && (response.exceededTransferLimit || (response.properties && response.properties.exceededTransferLimit)) && this.options.fetchAllFeatures) {
this._requestFeatures(bounds, coords, callback, offset + featureCollection.features.length);
}
},
this);
this);
},

_postProcessFeatures: function (bounds) {
Expand Down Expand Up @@ -228,14 +235,18 @@ export var FeatureManager = FeatureGrid.extend({
this.createLayers(features);
},

_buildQuery: function (bounds) {
_buildQuery: function (bounds, offset) {
var query = this.service
.query()
.intersects(bounds)
.where(this.options.where)
.fields(this.options.fields)
.precision(this.options.precision);

if (this.options.fetchAllFeatures && !isNaN(parseInt(offset))) {
query = query.offset(offset);
}

query.params['resultType'] = 'tile';

if (this.options.requestParams) {
Expand Down
4 changes: 2 additions & 2 deletions src/Tasks/Query.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,15 @@ export var Query = Task.extend({
this._cleanParams();

// services hosted on ArcGIS Online and ArcGIS Server 10.3.1+ support requesting geojson directly
if (this.options.isModern || isArcgisOnline(this.options.url)) {
if (this.options.isModern || (isArcgisOnline(this.options.url) && this.options.isModern === undefined)) {
this.params.f = 'geojson';

return this.request(function (error, response) {
this._trapSQLerrors(error);
callback.call(context, error, response, response);
}, this);

// otherwise convert it in the callback then pass it on
// otherwise convert it in the callback then pass it on
} else {
return this.request(function (error, response) {
this._trapSQLerrors(error);
Expand Down