I managed to download all the data from ArcGis REST Service, from FeatureServer service, using JavaScript.
I have all the data, featureserver json data, feature layers data, queried features data.
The problem I am facing is I can't create a FeatureLayer. I have featureSet, featureCollection, renderer and even array of features Graphic made from JSON.
I've read something of creating FeatureLayer from featureCollection, but the only result is an error: "Feature layer must be created with either a url or a source".
I tried to create a FeatureLayer from source, renderer, but nothing appears in on the map.
The JSON data is fetched in Javascript via fetch(). I saw somewhere a esriRequest method, but I am not sure if it will help since the json in response is exactly the same.
I am working with this data currently:
Fetch FeatureServer data:
async function getFeatureServerJSON(featureServerUrlString) {
const downloadedFeatureService = await getArcGisData(
featureServerUrlString + "?f=json"
);
const downloadedFeatureLayers = [];
for (let i = 0; i < downloadedFeatureService.layers.length; i++) {
downloadedFeatureLayers.push({
structure: await getArcGisData(featureServerUrlString + i + "?f=json"),
featureSet: await getArcGisData(
featureServerUrlString + i + "/query?f=json&where=1=1"
),
});
}
return {
featureService: downloadedFeatureService,
featureLayers: downloadedFeatureLayers,
};
}
Creating FeatureLayer:
const graphicFirstLayerArray = [];
for (const feature of cachedFeatureServer.featureLayers[0].featureSet
.features) {
graphicFirstLayerArray.push(Graphic.fromJSON(feature));
}
// console.log(graphicFirstLayerArray);
const { renderer } = cachedFeatureServer.featureLayers[0].structure.drawingInfo;
const fset = FeatureSet.fromJSON(cachedFeatureServer.featureLayers[0].featureSet);
const featureCollection = {
layerDefinition: cachedFeatureServer.featureLayers[0].structure,
featureSet: fset,
};
const fl = new FeatureLayer(featureCollection);
map.layers.add(fl);
Please help 🙂
Hi @wnukiewiczdev ,
Check out this sample about creating a feature layer from an array of graphics. I hope it helps. You need to set your array of graphics from the feature collection as the source property on the feature layer as well as define the fields and objectIdField.
Creating a FeatureLayer with client-side graphics requires the following steps:
const layer = new FeatureLayer({
source: graphics, // array of graphics objects
objectIdField: "OBJECTID",
fields: [{
name: "OBJECTID",
type: "oid"
}, {
name: "url",
type: "string"
}],
popupTemplate: {
content: "<img src='{url}'>"
},
renderer: { // overrides the layer's default renderer
type: "simple",
symbol: {
type: "text",
color: "#7A003C",
text: "\ue661",
font: {
size: 20,
family: "CalciteWebCoreIcons"
}
}
}
});
map.add(layer);
So, basically there is no automatic way to create FeatureLayer from JSON and I am forced to define each single parameter of the FeatureLayer?
I've done some changes to my feature layer data and it seems that I have features rendered on the map, but the problem is the points are outside the map completely.
Example x and y values of downloaded point:
The automatic way to do this is to create the feature layer using the url or portal item id for the service, not try and download the json and do all this manually 😀 Using the REST service endpoint has many additional performance benefits over loading all the data into a client side layer too. The service appears to be publicly available, so it could be as easy as this
const featureLayer = new FeatureLayer({
url: "https://services1.arcgis.com/RbMX0mRVOFNTdLzd/ArcGIS/rest/services/2020_Electric_Service_Area_web/FeatureServer/0"
});
map.add(featureLayer);
This codepen shows this service in a map in the correct location: https://codepen.io/sagewall/pen/rNEWVeP
If you knew the portal item id it would be even better as the layer would load with all of it's configured symbology, popups and other configurations set in the Map Viewer.
But going back to your question it sounds like in your case you probably need to set the correct spatial reference for the service. Looking at the REST endpoint the service is in
Try setting the spatialReference property in your feature layer to "26919" and hopefully they will show up as expected.
const featureLayer = new FeatureLayer({
spatialReference: {
wkid: 26919
},
.....
});
Some more info about spatial references can be found here
I know everything about the url and portalItem source for a FeatureLayer. The problem is that these two methods are server-side and my main goal is to cache somehow the data and make the application independent from the server hosting ArcGIS service.
I used a different layer for tests which was a point-type FeatureLayer. In that case I had to destructure all the necessary data from the JSON and render a client-side FeatureLayer using source property.
The problem with the data was that point coordinates were not fit for the mapview. It turned out that REST service gave me point coordinates in Web Mercator (in meters) and I needed to convert it o GPS longitude/latitude. Luckily Esri delivers something called webMercatorUtils, which was extremely helpful and did the work. With proper data and my own renderer I could display the Features on the map.
Even with hard-coded spatialReference, the points were still not displayed. The conversion helped.
Now I would like to work with polygons and different types of geometries. Hopefully it will be something similar.
Ahh, thanks for the additional background, sounds like a cool project. If you get it all working please share 🙂 The JS SDK doesn't support offline maps but you might want to look at the native SDKs they have full support for offline and partially offline apps. https://developers.arcgis.com/documentation/offline-mapping-apps/
I forgot to mention that there is a `fromJSON()` method on quite a few classes but not for the FeatureLayer itself. This will help create things like symbols and geometries.
https://developers.arcgis.com/javascript/latest/using-fromjson/
Thank you for your help and all the information you provided. It is good to know that I'm dealing with something not supported 😄