Select to view content in your preferred language

Creating FeatureLayer from offline JSON data.

379
7
07-25-2024 08:17 AM
wnukiewiczdev
Emerging Contributor

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:

https://services1.arcgis.com/RbMX0mRVOFNTdLzd/ArcGIS/rest/services/2020_Electric_Service_Area_web/Fe...


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 🙂

0 Kudos
7 Replies
Sage_Wall
Esri Contributor

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:

  1. Set an array of graphics on the FeatureLayer.source property. All graphics must have the same geometry type.
  2. Specify an array of field objects, which provide the schema (name, alias, and type) of each attribute field.
  3. Set the objectID field property to a field containing unique IDs for each feature in the source property.

 

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);

 

 

0 Kudos
wnukiewiczdev
Emerging Contributor

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:

x: 2570987.0918999985
y: -1556400.7952999994

That can't be longitude and latitude, so I need to convert it?
I've read something about spatial reference, but when I try to add it to my feature layer or feature geometry, nothing good happens.

To clear up, feature layer works, point can be rendered but only with proper x/y that I assign manually. When I add points using the x/y downloaded from the service, the values are completely out of range.
0 Kudos
Sage_Wall
Esri Contributor

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 

    Spatial Reference: 26919 (26919)

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

 

0 Kudos
wnukiewiczdev
Emerging Contributor

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.

0 Kudos
Sage_Wall
Esri Contributor

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/ 

0 Kudos
Sage_Wall
Esri Contributor

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/

wnukiewiczdev
Emerging Contributor

Thank you for your help and all the information you provided. It is good to know that I'm dealing with something not supported 😄

0 Kudos