Giter Site home page Giter Site logo

slutske22 / react-esri-leaflet Goto Github PK

View Code? Open in Web Editor NEW
37.0 37.0 5.0 2.22 MB

react components for esri-leaflet

Home Page: https://codesandbox.io/s/github/slutske22/react-esri-leaflet/tree/master/examples/ts

License: MIT License

TypeScript 100.00%
esri-leaflet leaflet react react-leaflet

react-esri-leaflet's People

Contributors

slutske22 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

react-esri-leaflet's Issues

Issue with refs + Typescript (TiledMapLayer)

Perhaps related to this issue, I'm having some issues with refs andTiledMapLayer. Minimal example of my code is below:

import React from 'react';
import { MapContainer, TileLayer, ZoomControl } from 'react-leaflet'
import { TiledMapLayer } from 'react-esri-leaflet';
import { TiledMapLayer as EsriTiledMapLayer } from 'esri-leaflet';
import { LatLngBoundsExpression, LatLngTuple, Map as LeafletMap, TileLayer as LeafletTileLayer } from 'leaflet';
import bbox from '@turf/bbox';
import "./Map.css";
import { useTrackedState } from '../../state';

export default function Map() {
    const state = useTrackedState();
    const [map, setMap] = React.useState<LeafletMap>();
    const esriLayerRef= React.useRef<EsriTiledMapLayer>(null);

    const bboxArray = bbox(JSON.parse(state.features));
    const corner1: LatLngTuple = [bboxArray[1], bboxArray[0]];
    const corner2: LatLngTuple = [bboxArray[3], bboxArray[2]];
    const bounds: LatLngBoundsExpression = [corner1, corner2];

    /** if panel is collapsed, reset the map and tile layer **/
    React.useEffect(() => {
        let tileLayer = esriLayerRef.current;
        if (map && tileLayer) {
            map.invalidateSize();
            tileLayer.redraw();
        }
    }, [state.panelCollapsed]);

    return (
        <MapContainer bounds={bounds} id="projectMap" zoomControl={false} whenCreated={setMap}>
                <TiledMapLayer
                    ref={navLayerRef}
                    maxNativeZoom={10} url="https://server.arcgisonline.com/ArcGIS/rest/services/the/layer"
                />
            <ZoomControl position='topright' />
        </MapContainer>
    );

}

Perhaps my tsconfig is too strict...but I'm receiving the following error:

Type 'RefObject<TiledMapLayer>' is not assignable to type 'Ref<RefObject<TiledMapLayer>> | undefined'.
  Type 'RefObject<TiledMapLayer>' is not assignable to type 'RefObject<RefObject<TiledMapLayer>>'.
    Property 'current' is missing in type 'TiledMapLayer' but required in type 'RefObject<TiledMapLayer>'.ts(2322)
[index.d.ts(81, 18): ]()'current' is declared here.
[index.d.ts(133, 9): ]()The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & TiledMapLayerOptions & RefAttributes<RefObject<TiledMapLayer>>'

Is there something going on with the way forwardRef is being used? Let me know if there's any more information I can provide.

Thanks -- and great work on this project!

Can't change basemap layer

I have an application with components in the following basic structure:

<MapContainer>
  <BasemapLayer name={mapType} />
</MapContainer>

In this case, mapType is created via useState().

I want to be able to change mapType (e.g., via a UI control) and have the basemap layer re-draw with the new layer.

However, when I try this, the basemap layer never updates, staying the same as it was when it started.

I made a minimal example of the problem here: https://codesandbox.io/s/prod-shadow-xokzy3?file=/src/App.tsx

I am very unfamiliar with React, so this is probably user error, but I'm not sure the best way to work around this issue.

Warning about Identify in esri-leaflet creating multiple callback scripts

This is not a problem per se with your code, but your code could possibly solve the bug in other code. (Or if you wish, I could take this to the esri-leaflet people.)

What happens is that each time you call identify, esri-leaflet creates a new jsonp callback script element. This continues ad infinitum. A quick solution is to capture the returned script id and immediately remove the element, as shown below. (This is okay, as the initial script include has already fired off the request. Another method is to remove it in your own callback.)

{
        let idInfo = myLayer.current.identify()
          .layers(layerParam)
          .tolerance(16)
          .on(theMap)
          .at(ev.latlng)
        .run(function(error:any, featureCollection:any, response:any)
        {
            if (response != undefined)
            {
                listItems(response.results);
            }
        });

        // delete the callback jsonp script
        if (idInfo && idInfo.id)
            document.getElementById(idInfo.id).remove();
}

This way, the DOM does not get filled up with old identify scripts. Another possiblity might be to somehow capture this method in your code and do the deletion for the user (??).

In any case, your users should be made aware of this, possibly by including a note or code in your examples.

Thanks again!
Kev

"build" command does not transpile output

Running into an issue with testing with mocha, where the code in the build folder contains ES6 style imports and causes tests to fail with:

$ mocha --recursive --extension=js,cjs,mjs,jsx -r @babel/register -r jsdom-global/register -r ignore-styles 'src/**/*.test.jsx'

/home/user/my-repo/node_modules/react-esri-leaflet/build/index.js:1
import EsriLeafletLayer from './EsriLeafletLayer';
^^^^^^

SyntaxError: Cannot use import statement outside a module

After cloning react-esri-leaflet and messing around with it, I found that adding --extensions \".tsx\" to transpile:main and using the build generated by that command allows the tests to function.

Is it intended that the code in the build folder contains non-transpiled output?

Example of WMTS ?

Sorry if this question makes no sense. I was wondering if there is an example of this package rendering WMTS data? I tried searching around but couldn't find any concrete examples.

Question: how to use setWhere or equivalent with a FeatureLayer❓

Hi, I'm trying to give a UI to allow the user to modify the default where clause in a <FeatureLayer/> I have not yet figured out how to make the map rerender properly after the variables in the where clause change.

I'm passing in the year as a prop to this functional component - and that does update the where clause - but the layer disappears from the <MapContainer/> and I am getting a 400 error about the query not being able to execute. If I trigger a re-render of the entire <TheMap/> component then it works. Was reading code doc for the setWhere

 * Sets the new where option and refreshes the layer to reflect the new where filter. Accepts an optional
             * callback and function context.
             */
            setWhere(where: string, callback?: FeatureCallbackHandler, context?: any): this;
            /**

Here is a snippet of what I'm currently doing. I may simply not understand react and re-rendering flow.

const TheMap = ({ year }) => {
    return (
        <MapContainer
      id="mapId"
      style={mapstyle}
      zoom={zoom}
      center={{ lat: lat, lng: lon }}
    >
      <MapEvents />
      <LayersControl position="topleft" collapsed={false}>
        <LayersControl.Overlay name="Point Defects" checked>
          <FeatureLayer
            cacheLayers={false}
            where={`pr > 1 AND setup_id LIKE '${year}%'`}
            pointToLayer={function (features) {
              return L.marker(features.geometry.coordinates.reverse(), {
                icon: makeIcon(colors[features.properties.pr], 4, "black", 30),
              });
            }}
            url="{featureServiceURL}",
            eventHandlers={{
              loading: () => console.log("loading features"),
              load: () => console.log("featurelayer loaded"),
            }}
          />
        </LayersControl.Overlay>
      </LayersControl>
    </MapContainer>
    )
}

Uncaught ReferenceError: y is not defined (Production)

When in development environment, the VectorBasemapLayer works as advertised. I am able to select the different basemaps to include with and without labels.

However, once in production environment, I am only getting the base layers with no overlays on top (labels, coloring, etc...).
The Dev console throws an uncaught reference error that y is not defined.

Could not resolve dependency: [ react-esri-leaflet , esri-leaflet , esri-leaflet-vector ]

Have any of you run into this issue using your latest version? Wondering how you might have resolved it.

Some Context...
I have react, react-dom, leaflet, react-leaflet, esri-leaflet already installed (see below for all package.json list). Then when I try to install react-esri-leaflet I get some dependency errors (see below for error output in terminal).
For reference, I am using the basic Create React App setup.

--- Error when npm install react-esri-leaflet ---
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/esri-leaflet
npm ERR! esri-leaflet@"^3.0.1" from the root project
npm ERR! peer esri-leaflet@"^3.0.1" from [email protected]
npm ERR! node_modules/react-esri-leaflet
npm ERR! react-esri-leaflet@"" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer esri-leaflet@"^2.3.0" from [email protected]
npm ERR! node_modules/esri-leaflet-vector
npm ERR! peer esri-leaflet-vector@"^3.0.0" from [email protected]
npm ERR! node_modules/react-esri-leaflet
npm ERR! react-esri-leaflet@"
" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

--- From my Package.json ---
"dependencies": {
"@emotion/css": "^11.1.3",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"esri-leaflet": "^3.0.1",
"leaflet": "^1.7.1",
"lodash.every": "^4.6.0",
"lodash.filter": "^4.6.0",
"lodash.get": "^4.4.2",
"lodash.has": "^4.5.2",
"lodash.pick": "^4.4.0",
"lodash.set": "^4.3.2",
"lodash.unset": "^4.5.2",
"mobx": "^6.3.0",
"mobx-react-lite": "^3.2.0",
"nanoid": "^3.1.22",
"page": "^1.11.6",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-icons": "^4.2.0",
"react-leaflet": "^3.1.0",
"react-scripts": "4.0.3",
"web-vitals": "^1.0.1"
}

BasemapLayer is deprecated

I'm getting error in VsCode indicating that BasemapLayer is deprecated and I should used L.esri.Vector... instead.

"Suggestions" show different results than the actual "results"

Results in event "results" are different than the results shown in the "geocoder-control-suggestions".

These are the results when I type in "Botter,":
image

The "response.suggestions" in the "requestsuccess" function is always an empty array.
But it does fill the "geocoder-control-suggestions" with correct suggestions.

When I press enter, the "results" event returns an array of 4 items, which were not shown in the "suggestions".
This is the object which is returned in the "results" event:

[
    {
        "text": "De Botter",
        "bounds": {
            "_southWest": {
                "lat": 52.29370000000005,
                "lng": 5.229480000000076
            },
            "_northEast": {
                "lat": 52.303700000000056,
                "lng": 5.239480000000076
            }
        },
        "score": 97.75,
        "latlng": {
            "lat": 52.29870000000005,
            "lng": 5.234480000000076
        },
        "properties": {
            "Loc_name": "World",
            "Status": "T",
            "Score": 97.75,
            "Match_addr": "De Botter",
            "LongLabel": "De Botter, Havenstraat 15, 1271 AB Huizen, NLD",
            "ShortLabel": "De Botter",
            "Addr_type": "POI",
            "Type": "Bar or Pub",
            "PlaceName": "De Botter",
            "Place_addr": "Havenstraat 15, 1271 AB Huizen",
            "StName": "Havenstraat",
            "StAddr": "Havenstraat 15",
            "Postal": "1271 AB",
            "Country": "NLD",
            "CntryName": "Nederland",
            "LangCode": "DUT"
        }
    },
    {
        "text": "De Botter",
        "bounds": {
            "_southWest": {
                "lat": 51.86031000000008,
                "lng": 4.614950000000074
            },
            "_northEast": {
                "lat": 51.87031000000008,
                "lng": 4.624950000000074
            }
        },
        "score": 97.75,
        "latlng": {
            "lat": 51.86531000000008,
            "lng": 4.619950000000074
        },
        "properties": {
            "Loc_name": "World",
            "Status": "T",
            "Score": 97.75,
            "Match_addr": "De Botter",
            "LongLabel": "De Botter, Voorn 11, 2986 JA Ridderkerk, NLD",
            "ShortLabel": "De Botter",
            "Addr_type": "POI",
            "Type": "School",
            "PlaceName": "De Botter",
            "Place_addr": "Voorn 11, 2986 JA Ridderkerk",
            "StName": "Voorn",
            "StAddr": "Voorn 11",
            "Postal": "2986 JA",
            "Country": "NLD",
            "CntryName": "Nederland",
            "LangCode": "DUT"
        }
    },
    {
        "text": "De Botter",
        "bounds": {
            "_southWest": {
                "lat": 52.34574000000003,
                "lng": 5.610380000000073
            },
            "_northEast": {
                "lat": 52.35574000000003,
                "lng": 5.620380000000073
            }
        },
        "score": 97.75,
        "latlng": {
            "lat": 52.35074000000003,
            "lng": 5.615380000000073
        },
        "properties": {
            "Loc_name": "World",
            "Status": "T",
            "Score": 97.75,
            "Match_addr": "De Botter",
            "LongLabel": "De Botter, Strandboulevard West, 3841 CS Harderwijk, NLD",
            "ShortLabel": "De Botter",
            "Addr_type": "POI",
            "Type": "International Food",
            "PlaceName": "De Botter",
            "Place_addr": "Strandboulevard West, 3841 CS Harderwijk",
            "StName": "Strandboulevard West",
            "StAddr": "Strandboulevard West",
            "Postal": "3841 CS",
            "Country": "NLD",
            "CntryName": "Nederland",
            "LangCode": "DUT"
        }
    },
    {
        "text": "De Botter",
        "bounds": {
            "_southWest": {
                "lat": 52.78139000000004,
                "lng": 5.836760000000022
            },
            "_northEast": {
                "lat": 52.79139000000004,
                "lng": 5.846760000000022
            }
        },
        "score": 97.75,
        "latlng": {
            "lat": 52.78639000000004,
            "lng": 5.841760000000022
        },
        "properties": {
            "Loc_name": "World",
            "Status": "T",
            "Score": 97.75,
            "Match_addr": "De Botter",
            "LongLabel": "De Botter, Burchtstraat 3, 8374 KC Kuinre, NLD",
            "ShortLabel": "De Botter",
            "Addr_type": "POI",
            "Type": "Bar or Pub",
            "PlaceName": "De Botter",
            "Place_addr": "Burchtstraat 3, 8374 KC Kuinre",
            "StName": "Burchtstraat",
            "StAddr": "Burchtstraat 3",
            "Postal": "8374 KC",
            "Country": "NLD",
            "CntryName": "Nederland",
            "LangCode": "DUT"
        }
    }
]

I removed some of the unnecessary properties.

My code:

<EsriLeafletGeoSearch
          useMapBounds={false}
          position={control.position}
          allowMultipleResults={true}
          expanded={true}
          eventHandlers={{
            results: (data) => {
              // ... me creating a marker for each data result..
            }
          }}
          placeholder={t("Zoeken naar plaatsen of adressen")}
          title={t("Locatie zoeken")}
          providers={{
            arcgisOnlineProvider: {
              apikey: ... my apikey,
              countries: ["NLD"],
              maxResults: 10
            }
          }}
/>

When I set "AllowMultipleResults" to false, the suggestions stay the same but when I press enter, I receive 0 results.

I also tried setting the "categories" but this has no effect.

In short: the "suggestions" show different results than the actual "results".

Versions:

 "esri-leaflet": "3.0.10",
    "esri-leaflet-geocoder": "3.1.4",
    "esri-leaflet-vector": "4.0.1",
    "leaflet": "1.9.3",
    "react-esri-leaflet": "2.0.1",
    "react-leaflet": "4.2.1"

Thanks

Cannot useRef with functional components

First, thanks for the library. One of the examples shows a useRef to get a handle to a layer. However, when I tried that with DynamicLayer so that I could trigger an Identify task later, React of course complained that I could not use refs with such a component.

Am I missing something? Thanks for any help. If this is the wrong venue for such a question, please direct to the right spot. Thank you.

Geosearch Multiple Providers of same type ?

Perhaps (probably?) I'm doing something wrong but here is my scenario.

Using the EsriLeafletGeoSearch plugin, we configure providers by passing an object who's keys are parsed into the provider type that esri-leaflet-geocoder supports.

so example object looks something like this:

                mapServiceProvider: {
                        token: token,
                        url: "https://server/server/rest/services/folder/service/MapServer",
                        layers: [21],
                        searchFields: ["id"],
                        label: "Feature X",
                        searchMode: "strict",
                        bufferRadius: 10,
                        maxResults: 20,
                        formatSuggestion: function (feature) {
                            return `${feature.properties.id}` || null;
                        },
                    },
              // mapServiceProvider: {
                    //     token: token,
                    //     url: "https://server/server/rest/services/folder/service/MapServer",
                    //     layers: [3],
                    //     searchFields: ["name", "id"],
                    //     label: "Feature Y",
                    //     searchMode: "startsWith",
                    //     bufferRadius: 10,
                    //     maxResults: 20,
                    //     formatSuggestion: function (feature) {
                    //         return `${feature.properties.id} ${feature.properties.name}` || null;
                    //     },
                    // },

Since the object is then parsed using Object.keys(object) to tell ELG which provider type we want being one of

  • arcgisOnlineProvider
  • featureLayerProvider
  • mapServiceProvider
  • geocodeServiceProvider

It appears to me that one cannot configure 2 or more of the same type of provider this way because you'd have to create an object with duplicate keys and I think the last one in wins.

In the ELG documentation here - it looks like it can support multiple providers of the same type maybe?
https://developers.arcgis.com/esri-leaflet/api-reference/controls/geosearch/#providers

But it looks like it would require us passing in an array of objects so we're not relying on the keys of an object for provider type and instead we use a key/value pair that defines the provider type.

So would that be changing things around here?

const providers = Object.keys(providersProp).map((provider) => {

Perhaps it would accept something like this example below to configure multiple of the same type of providers?

[
    {
        "type": "mapServiceProvider",
        "options": {
            "token": token,
            "url": "https://server/server/rest/services/folder/service/MapServer",
            "layers": [21],
            "searchFields": ["id"],
            "label": "Feature X",
            "searchMode": "strict",
            "bufferRadius": 10,
            "maxResults": 20,
            "formatSuggestion": function (feature) {
                return `${feature.properties.id}` || null;
            },
        }
    },
    {
        "type": "mapServiceProvider",
        "options": {
            "token": token,
            "url": "https://server/server/rest/services/folder/service/MapServer",
            "layers": [3],
            "searchFields": ["name", "id"],
            "label": "Feature X",
            "searchMode": "strict",
            "bufferRadius": 10,
            "maxResults": 20,
            "formatSuggestion": function (feature) {
                return `${feature.properties.id} ${feature.properties.name}` || null;
            },
        }
    },
]

Thanks for listening.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.