esri-leaflet
Version:
Leaflet plugins for consuming ArcGIS Online and ArcGIS Server services.
243 lines (211 loc) • 7.64 kB
JavaScript
import { point, latLng } from "leaflet";
import { Task } from "./Task.js";
import {
warn,
responseToFeatureCollection,
isArcgisOnline,
extentToBounds,
_setGeometry,
} from "../Util.js";
export const Query = Task.extend({
setters: {
offset: "resultOffset",
limit: "resultRecordCount",
fields: "outFields",
precision: "geometryPrecision",
featureIds: "objectIds",
returnGeometry: "returnGeometry",
returnM: "returnM",
transform: "datumTransformation",
token: "token",
},
path: "query",
params: {
returnGeometry: true,
where: "1=1",
outSR: 4326,
outFields: "*",
},
// Returns a feature if its shape is wholly contained within the search geometry. Valid for all shape type combinations.
within(geometry) {
this._setGeometryParams(geometry);
this.params.spatialRel = "esriSpatialRelContains"; // to the REST api this reads geometry **contains** layer
return this;
},
// Returns a feature if any spatial relationship is found. Applies to all shape type combinations.
intersects(geometry) {
this._setGeometryParams(geometry);
this.params.spatialRel = "esriSpatialRelIntersects";
return this;
},
// Returns a feature if its shape wholly contains the search geometry. Valid for all shape type combinations.
contains(geometry) {
this._setGeometryParams(geometry);
this.params.spatialRel = "esriSpatialRelWithin"; // to the REST api this reads geometry **within** layer
return this;
},
// Returns a feature if the intersection of the interiors of the two shapes is not empty and has a lower dimension than the maximum dimension of the two shapes. Two lines that share an endpoint in common do not cross. Valid for Line/Line, Line/Area, Multi-point/Area, and Multi-point/Line shape type combinations.
crosses(geometry) {
this._setGeometryParams(geometry);
this.params.spatialRel = "esriSpatialRelCrosses";
return this;
},
// Returns a feature if the two shapes share a common boundary. However, the intersection of the interiors of the two shapes must be empty. In the Point/Line case, the point may touch an endpoint only of the line. Applies to all combinations except Point/Point.
touches(geometry) {
this._setGeometryParams(geometry);
this.params.spatialRel = "esriSpatialRelTouches";
return this;
},
// Returns a feature if the intersection of the two shapes results in an object of the same dimension, but different from both of the shapes. Applies to Area/Area, Line/Line, and Multi-point/Multi-point shape type combinations.
overlaps(geometry) {
this._setGeometryParams(geometry);
this.params.spatialRel = "esriSpatialRelOverlaps";
return this;
},
// Returns a feature if the envelope of the two shapes intersects.
bboxIntersects(geometry) {
this._setGeometryParams(geometry);
this.params.spatialRel = "esriSpatialRelEnvelopeIntersects";
return this;
},
// if someone can help decipher the ArcObjects explanation and translate to plain speak, we should mention this method in the doc
indexIntersects(geometry) {
this._setGeometryParams(geometry);
this.params.spatialRel = "esriSpatialRelIndexIntersects"; // Returns a feature if the envelope of the query geometry intersects the index entry for the target geometry
return this;
},
// only valid for Feature Services running on ArcGIS Server 10.3+ or ArcGIS Online
nearby(latlng, radius) {
latlng = latLng(latlng);
this.params.geometry = [latlng.lng, latlng.lat];
this.params.geometryType = "esriGeometryPoint";
this.params.spatialRel = "esriSpatialRelIntersects";
this.params.units = "esriSRUnit_Meter";
this.params.distance = radius;
this.params.inSR = 4326;
return this;
},
where(string) {
// instead of converting double-quotes to single quotes, pass as is, and provide a more informative message if a 400 is encountered
this.params.where = string;
return this;
},
between(start, end) {
this.params.time = [start.valueOf(), end.valueOf()];
return this;
},
simplify(map, factor) {
const mapWidth = Math.abs(
map.getBounds().getWest() - map.getBounds().getEast(),
);
this.params.maxAllowableOffset = (mapWidth / map.getSize().y) * factor;
return this;
},
orderBy(fieldName, order) {
order = order || "ASC";
this.params.orderByFields = this.params.orderByFields
? `${this.params.orderByFields},`
: "";
this.params.orderByFields += [fieldName, order].join(" ");
return this;
},
run(callback, context) {
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) && 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
}
return this.request(function (error, response) {
this._trapSQLerrors(error);
callback.call(
context,
error,
response && responseToFeatureCollection(response),
response,
);
}, this);
},
count(callback, context) {
this._cleanParams();
this.params.returnCountOnly = true;
return this.request(function (error, response) {
callback.call(this, error, response && response.count, response);
}, context);
},
ids(callback, context) {
this._cleanParams();
this.params.returnIdsOnly = true;
return this.request(function (error, response) {
callback.call(this, error, response && response.objectIds, response);
}, context);
},
// only valid for Feature Services running on ArcGIS Server 10.3+ or ArcGIS Online
bounds(callback, context) {
this._cleanParams();
this.params.returnExtentOnly = true;
return this.request((error, response) => {
if (response && response.extent && extentToBounds(response.extent)) {
callback.call(
context,
error,
extentToBounds(response.extent),
response,
);
} else {
error = {
message: "Invalid Bounds",
};
callback.call(context, error, null, response);
}
}, context);
},
distinct() {
// geometry must be omitted for queries requesting distinct values
this.params.returnGeometry = false;
this.params.returnDistinctValues = true;
return this;
},
// only valid for image services
pixelSize(rawPoint) {
const castPoint = point(rawPoint);
this.params.pixelSize = [castPoint.x, castPoint.y];
return this;
},
// only valid for map services
layer(layer) {
this.path = `${layer}/query`;
return this;
},
_trapSQLerrors(error) {
if (error) {
if (error.code === "400") {
warn(
"one common syntax error in query requests is encasing string values in double quotes instead of single quotes",
);
}
}
},
_cleanParams() {
delete this.params.returnIdsOnly;
delete this.params.returnExtentOnly;
delete this.params.returnCountOnly;
},
_setGeometryParams(geometry) {
this.params.inSR = 4326;
const converted = _setGeometry(geometry);
this.params.geometry = converted.geometry;
this.params.geometryType = converted.geometryType;
},
});
export function query(options) {
return new Query(options);
}
export default query;