Vizzuality / layer-manager

A library to get a layer depending on provider and layer spec
https://layer-manager-docs.vercel.app
MIT License
18 stars 12 forks source link

Interactive ESRI Layers #142

Closed jlev closed 2 years ago

jlev commented 2 years ago

Hi, I'm working on a project that uses layer-manager to display data from numerous sources. We have had a feature request to allow adding ESRI FeatureServer layers in an interactive manner. I see there used to be some code in this repository for ESRI layers, and wonder if that is still supported.

I have created a simple layer provider following the docs, like this:

import { fetch } from 'layer-manager/dist/layer-manager';
import omit from 'lodash/omit';

export function ESRIProvider(layerModel, layer, resolve, reject) {
  const { source } = layerModel;
  const { provider, type } = source;

  // add query, format and projection to provider url
  const query = provider.query ? encodeURIComponent(provider.query) : 'where=1=1';
  const format = type || 'geojson';
  const srid = '4326';
  const dataUrl = `${provider.url}/0/query?${query}&outFields=*&outSR=${srid}&f=${format}`;

  fetch('get', dataUrl, provider.options, layerModel)
    .then(response => {
      const data = {
        ...layer,
        source: {
          ...omit(layer.source, 'provider'),
          type: type,
          data: response,
        },
      };
      return resolve(data);
    })
    .catch(e => {
      reject(e);
    });
}

The provider url is https://data-gis.unep-wcmc.org/server/rest/services/ProtectedSites/The_World_Database_of_Protected_Areas/FeatureServer

However these features are not appearing on the map, perhaps because the styling is not present in the geojson features.

Alternatively, is it possible to use a separate library (https://github.com/rowanwins/mapbox-gl-arcgis-featureserver) that relies on mapbox-gl's addLayer call, and pass that new layer into layer-manager directly?

mbarrenechea commented 2 years ago

In the specific case you shared you don't need a provider. You are dealing with a geojson layer. You can also parametrize the data url, as soon as it changes, the layer will be updated.

{
  id: 'esri-geojson',
  type: 'geojson',
  source: {
    type: 'geojson',
    data: "https://data-gis.unep-wcmc.org/server/rest/services/ProtectedSites/The_World_Database_of_Protected_Areas/FeatureServer/0/query?where=1=1&outFields=*&outSR=4326&f=geojson"
  },
  render: {
    layers: [
      {
        type: 'circle',
        paint: {
          'circle-color': '#F00'
        }
      }
    ]
  }
}

This is the result

image

About creating a ERSI provider: It's in our roadmap to support ArcGIS FeatureServer or MapServer. We will probably get some inspiration from the library you shared.

jlev commented 2 years ago

Ah, it seems like my problem was with the styling of the layer, instead of getting the data to load. I actually want to display the outlines of each park, so needed to be querying FeatureServer for the polygons instead of points (endpoint /1/ instead of /0/).

The geojson response and rendering is quite slow, so this may not be a good solution for this client. It would be great to get future support for ESRI's PBF output, which seems like it might be faster to generate. That library I linked also appears to help with pagination. Right now the result is limited to 2000 features, which is more than this layer contains.

mbarrenechea commented 2 years ago

@jlev Do you have any possibililty to use it as vector tiles? That would be for sure the fastest way to consume them.

You will simply use a vector source and use their tiles. Here you have an example using the example ARCGis provides. In your case, you are trying to show the world protected areas. If I'm not wrong there are around 300.000 polygons. The only way to show this on a map is by using vector or raster tiles.

{
  id: 'esri-vector',
  type: 'vector',
  source: {
    type: 'vector',
    tiles: ['https://vectortileservices3.arcgis.com/GVgbJbqm8hXASVYi/ArcGIS/rest/services/Santa_Monica_Mountains_Parcels_Styled/VectorTileServer/tile/{z}/{y}/{x}.pbf']
  },
  render: {
    layers: [
      {
        type: 'fill',
        'source-layer': 'Santa_Monica_Mountains_Parcels_Styled',
        paint: {
          'fill-color': '#FF0',
        }
      },
      {
        type: 'line',
        'source-layer': 'Santa_Monica_Mountains_Parcels_Styled',
        paint: {
          'line-color': '#F00',
          'line-width': 1,
        }
      }
    ]
  },
}
jlev commented 2 years ago

Thanks @mbarrenechea, I was able to show the speed difference between geojson and pbf and convince the client to enable the VectorTileServer for the layers in question. Now it works (although the z/y/x ordering tripped me up for a minute).

jlev commented 2 years ago

Hey @mbarrenechea, one more question here. I've been able to get many different vector layers to display using an ESRI VectorTileServer's .pbf output, but none appear to have attribute data attached. Based on this talk, it seems like that's an intentional decision on their part.

I can query a FeatureServer for a given point and get back GeoJSON that contains attributes, but I'm not sure how to connect the two in layer-manager. Is this something that a custom provider would help with?

mbarrenechea commented 2 years ago

Hey @jlev,

I can query a FeatureServer for a given point and get back GeoJSON that contains attributes, but I'm not sure how to connect the two in layer-manager. Is this something that a custom provider would help with?

The layer manager is not responsible of the interactivity of your app. I don't see what you want to achieve here. What is the purpose of getting this data? Do you want to show a tooltip or something like that?

jlev commented 2 years ago

I'm using react-map-gl with PluginMapboxGl. Haven't switched to maplibre (yet).

The vector tiles don't show attributes when I decode them with tippecanoe. Eg: https://data-gis.unep-wcmc.org/server/rest/services/Hosted/WDPA_Marine_Coastal/VectorTileServer/tile/1/1/1.pbf gives { "type": "FeatureCollection", "properties": { "zoom": 1, "x": 1, "y": 1, "compressed": false }, "features": [ { "type": "FeatureCollection", "properties": { "layer": "Chingaza_0", "version": 2, "extent": 4096 }, "features": [ { "type": "Feature", "properties": { }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 32.695312, -84.196507 ], [ 32.871094, -84.196507 ], [ 33.046875, -84.196507 ], [ 32.695312, -84.231947 ], [ 32.519531, -84.231947 ], [ 32.519531, -84.214254 ], [ 32.519531, -84.196507 ], [ 32.695312, -84.196507 ] ] ] } } ] } ] }

This is for the UNBL Biodiversity Lab platform, which currently stores their data on Carto but is interested in moving to ESRI. The same tile from there includes properties, so the layer's legendConfig and interactionConfig can use those to style features and show data in popups.

Happy to discuss further via email or slack if this is no longer related to the library. I'm josh@impactobservatory.com